可爱的程序猿 - CoderYuan.com

改变世界的猿类——袁国正的个人网站

0%

数据库在 App 中的作用

移动 App 的数据库与 Server 数据库不同,其主要目的是为了缓存一些数据,如:历史消息、数据打点、列表数据缓存等,宗旨都是为优化用户体验建立一套简单的数据基础

由于 SQLite 完全开源,且比较轻量(不需要像 MySQL 这样建立一个单独的进程,直接操作 DB 文件),目前,在各类移动端操作系统(包括不限于 Android、iOS、Windows)当中,都会内置 SQLite,以便开发者存取结构化数据

于是,围绕 SQLite 展开的开发框架也越来越多,比如:iOS 上的 FMDB、以及 Apple 官方的 CoreData,Android 上的 SQLiteOpenHelper,以及基于它构建的 GreenDAO、Android 官方的 Room 等等,这些框架使得开发者不需要关注 SQLite 中 C/C++ 一层的 API,大幅降低了移动端数据库的开发成本,使得数据存取变得容易

虽然 SQLite 用途广泛,但 SQLite 也存在着一些性能问题,这些性能问题在数据量比较庞大时,体现地更为明显,近几年也出现了一些面向移动端,基于 NoSQL 或对 SQLite 进行改进数据库框架,如:Realm、WCDB……

那么在 KMM 中,如果需要操作数据库,使用 SQLDelight 框架,无疑是目前比较好的选择

阅读全文 »

为什么需要在 KMM 中处理多线程?

我们使用 KMM,通常是处理和 UI 无关的业务逻辑,所以多数情况是网络请求、数据缓存、文件读写等操作,为了不影响 UI 绘制,这些操作往往都会在异步线程中执行,而 KMM 模块的线程切换,调用方肯定是不应该去管理的,所以需要探索一种在 KMM 中比较靠谱的多线程处理方式

可行的多线程切换方式

  1. 协程(kotlinx-coroutines

    Kotlin 协程不依赖于 JVM 实现,可以应用在 Kotlin Native 项目当中,不需要再实现平台差异化代码,且协程开销与线程相比较小,可以满足异步任务的需求

    但协程也有一些问题,比如,执行顺序不好控制,如果需要异步且串行地执行一系列任务,使用协程并不有效地、方便地控制执行顺序

    另外,协程对 Kotlin Native 支持的并不像 JVM 上那么完美(尤其是多线程的实现),有待进一步完善

  2. expect + Block

    将需要异步执行的任务包成一个 Kotlin 闭包,实际将其扔进工作线程的方法,由 expect + actual 组合的形式实现,Android 端可以利用线程池,iOS 端可以使用 GCD

    这种方法归根结底还是使用了现有比较成熟的多线程方案,执行顺序比较容易控制,但需要一定的基础能力建设,需要编写一些平台差异化代码

  3. 第三方库

    KMM 官方推荐 CoroutineWorkerReaktive

    CoroutineWorker 是对 Kotlin 协程的封装,迭代比较少,不算比较稳定的方案

    Reaktive 采用 RxJava 的实现思想,Native 底层采用 Kotlin Native 实现,目前看功能还算比较方便,但框架相对较重

阅读全文 »

KMM 的依赖类型

KMM 的依赖根据平台分为三类,分别是 Common 依赖、Android 依赖、iOS 依赖,其中 Common 依赖顾明思议,是用于通用逻辑的,这种依赖只能使用基于最标准的 Kotlin 底层能力(不可以耦合 JVM、JS)构建

例如,在 Android 端上比较常用的 Kotlin Reflect、OkHTTP、GSON、Fresco,在 iOS 上比较常用的 AFNetworking、YYModel 之类的库,都不能直接用在 KMM 模块的 Common 代码库中

那么,上面说的这些库能不能让 KMM 继续使用?或者有没有直接可以使用的库?。。。

答案当然是肯定的!

使用 Common 或 Android 依赖

Common 依赖

首先是需要找到能够使用的第三方库,这里推荐一些比较优秀、可以直接使用的 KMM 库,不过这些库可能还需要在各平台的代码库中添加依赖项,以便实现差异化功能或者平台耦合能力

官方 JSON 解析库:https://github.com/Kotlin/kotlinx.serialization

HTTP 请求库:https://github.com/ktorio/ktor

SQLite 操作库:https://github.com/cashapp/sqldelight

这些库的依赖也非常简单,和普通的 Gradle 依赖类似,只需要在 KMM 模块根目录的 build.gradle.kts 文件中添加即可,如下图所示,在 commonMain 变量后面的闭包中,新建一个 dependencies 闭包,即可以按照常规的 Gradle 依赖形式,添加 ktor 的 Common 依赖

在 Sync 成功后,便可以使用 Common 能力了

阅读全文 »

平台差异化代码的使用场景

由于 KMM 运行在各平台时,实际上是翻译成了各平台专用的库,如:Android 上就会将共享模块编译成 Dalvik Bytecode 然后打包成 AAR 文件,而 iOS 上会打包成 Apple Framework,所以,一些平台相关的、不可共享的具体实现代码,就必须利用各平台的 API 来实现

举个简单的例子,公共模块有一个统一的业务逻辑——获取手机型号,控制逻辑可以在 KMM 的 common 代码库中实现,且它并不关系具体的实现逻辑,而实际需要获取手机型号字符串的方法,Android 需要调用 android.os.Build.MODEL 获取,而 iOS 需要通过 UIDevice.current.model 来获取

类似的平台强相关功能,就需要在 KMM 中利用平台差异化代码实现

差异化代码的基本实现

这里需要再次引用 Kotlin 官方的一张图

阅读全文 »

为什么要在现有工程中集成?

直接用 KMM 插件生成的工程不香嘛?为什么还要讲在原有的工程中集成?

不香,确实不香!

  • 默认工程结构局限性高

    1. 由 KMM 插件建立的工程,默认使用 Kotlin(*.kts 文件)进行 Gradle 配置,虽然用 Android Studio 新建一个 Android 工程会默认使用 kts,但很多项目现在都还在使用 Groovy,要改回去也需要一定工作量和学习成本
    2. 默认建立的 iOS 工程使用 Swift UI,目前大多数 iOS App 都会使用代码开发 UI,并没有使用 Storyboard、IB、Swift UI,而且国内很多公司都还在使用 Objective-C,同时 Swift 与 Objective-C 的交互并不像 Kotlin 和 Java 那样简单,所以彻底迁移到 Swift,还需要一定时间
  • 工程目录不易维护

    默认的工程类似一个独立的 Android App 工程,KMM 模块以 Gradle 模块形式依赖在 Android 主 App Module 当中,而 iOS 工程则是直接放在一个目录下,iOS 工程往往规模都比较庞大,且缺少像 Gradle 这样的工程管理框架,且 Xcode 工程索引文件在多人开发时,经常需要解决冲突,如果将 iOS 工程也放在整个 Android 工程目录中,后续将十分难以维护

阅读全文 »

什么是KMM?

KMM 全称:Kotlin Multiplatform Mobile,是基于 Kotlin 语言进行多平台开发的一套技术框架,它和 Kotlin Native(简称 KN)有一定联系,但 KMM 主要面相移动端开发,即:Android、iOS、Web,而 KN 则主要面相 Linux、macOS、Windows 等

当然,KMM 在 iOS 平台的实现,离不开 Kotlin Native,Kotlin 代码最终会在 iOS 工程中生成一套 Framework 库,可供 Objective-C、Swift 进行调用

KMM 宗旨是使用 Kotlin 语言和技术栈,开发一套可以在多平台之间共享的代码库,用来构建统一的代码逻辑,而不用针对各个平台都去实现自己的一套,从而导致人力的浪费

这里引用 Kotlin 官网的一张图来说明 Kotlin 多平台的工作原理

Kotlin 多平台
阅读全文 »

先讲讲怎么回事

不知道怎么的,大概是从19年双十一前,我在家里刷淘宝(天猫、闲鱼等)的时候,图片经常加载的特别慢,家里是北京电信的100M宽带,另外还有一张电信的手机卡,无论宽带还是4G,图片都刷的很慢,网速正常,SpeedTest测试速度都是正常的,其他App也都OK

taobao-image

部分家里使用电信宽带的同事也遇到了类似的问题,但都以为是家里网速的问题,所以也没有向淘宝进行反馈,只是在需要的时候,切成4G使用罢了

今年5月宽带到期,由于淘宝的问题,差点就换了联通的,但由于联通略贵(500M,166/月),电信(200M,600+/年),而且疫情期间,懒得折腾了,直接续费吧

于是就想着怎么解决一下淘宝图片的问题

阅读全文 »

1 介绍

本规范参考Android官方Kotlin编码规范,旨在为Kotlin开发人员提供编码风格上的指导,仅供参考,如果翻译上的失误或建议,欢迎反馈!

2 源文件规范

2.1 文件编码

  • 所有源文件必须使用UTF-8进行编码

2.2 文件命名

  • 所有源文件必须使用.kt作为扩展名

  • 如一个源码文件仅包含一个顶级类,则该文件应当以这个定级类的类名作为文件名,如包含多个顶级定义,请选择一个能够描述该文件内容的名字作为文件名

2.3 特殊字符

2.3.1 空格

  • 除了换行符之外,ASCII空格(0x20)是唯一合法的空格字符

    • 所有在源代码中(包括字符、字符串以及注释中)出现的其他空格字符都需要转义
    • Tab不可以用于缩进

2.3.2 特殊转义字符

  • 任何含有特殊意义的转义字符,如:\b\n\r\t\'\''\\\$等,不可以使用Unicode进行转义
阅读全文 »

为什么HTTPS不能抓包了?

Google在Android 7.0以后的版本中,添加了“网络安全配置(Network security configuration)”的相关配置项。其旨在增强App的安全性,可以避免TargetSDK版本>=N的App内部网络请求在非测试环境下被恶意抓包。

Network Sercurity Configuration对安全性的保证,主要是通过以下几个途径:是否允许明文HTTP请求(非HTTPS)、HTTPS证书(区分系统、用户)信任设置、域名以及App的Debug或Release配置,只有符合Manifest中配置的NetworkConfig字段内容下的条件,才可以进行正常的HTTP请求,如果需要使用Charles、Fiddler等工具进行抓包,也需要利用NetworkConfig来配置可以信任的证书,否则HTTPS请求在CONNECT阶段,就会返回错误,同时LogCat会打印出类似以下的错误信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Caused by: java.security.cert.CertificateException: xxx.
at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:661)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:539)
at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:605)
at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:495)
at com.android.org.conscrypt.TrustManagerImpl.checkServerTrusted(TrustManagerImpl.java:321)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:113)
at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:87)
at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:116)
at com.huawei.secure.android.common.ssl.SecureX509TrustManager.checkServerTrusted(:105)
at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:212)
at com.android.org.conscrypt.ConscryptFileDescriptorSocket.verifyCertificateChain(ConscryptFileDescriptorSocket.java:404)
at com.android.org.conscrypt.NativeCrypto.SSL_do_handshake(Native Method)
at com.android.org.conscrypt.NativeSsl.doHandshake(NativeSsl.java:375)

通常,Android开发者会将NetworkConfig按照以下XML文件进行配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<!-- 允许明文HTTP(非HTTPS)请求 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 其他情况只允许信任系统内置证书 -->
<certificates src="system"/>
</trust-anchors>
</base-config>
<!-- 仅Debug包允许用户证书 -->
<debug-overrides>
<trust-anchors>
<certificates src="user"/>
</trust-anchors>
</debug-overrides>
</network-security-config>

然而对于开发者来说,通常App发版上线会选择使用Release版本的安装包,如果希望对Release包抓包,只能使用Android 6.0及以下的手机,这样一来,有时候出现线上问题,便无法进行HTTPS抓包,并不利于测试和修正

阅读全文 »

由来

一个月前,剁手了AMD Ryzen Threadripper 2990WX(官网),这个处理器的参数着实牛逼,32核心64线程,总共80MB的缓存,可以说秒杀目前所有的桌面级处理器了!狠了狠心,搞了一台,辅以32GB DDR4 3200MHz内存和970 EVO NVMe SSD,经过一番折腾(无CPU刷BIOS、装Windows/Linux系统),最终确定使用Windows 10专业工作站版作为日常开发使用。

Cinebench R15跑分:

R15跑分

CPU-Z跑分:

CPU-Z

虽然分数不像网上那些人跑得那么高,但也是相当猛了,再加上任务管理器64个框框,心里十分舒坦!

阅读全文 »