iOS Release 版本开启调试功能

2020-05-03  本文已影响0人  微微笑的蜗牛

iOS 开发中,对外发布的 TestFlight 版或者正式版都是以 Relase 方式构建。而我们一般会在 Debug 模式下开启某些调试功能或打印日志,但是这些操作在 Release 无效。

当我们需要在 Release 版本中启用调试功能时,就不太方便了。而解决这个问题似乎没有很优雅的方式。

在读过 How to Enable Custom Debugging in Release Builds 这篇文章后,发现一个比较新奇的方法。

常规方式

文章前半部分提供了几种可能的方式,比如:

  1. 使用一个新的配置定义 TESTFLIGHT
    在发版本的时候打两个包,一个是开启 TESTFLIGHT 配置,另一个关闭 TESTFLIGHT。但这并不能很好的区分哪个包对应的是什么配置。

  2. 硬编码 userId
    只对指定的 userId 生效。但添加/删除需要修改 userId 列表,且有些功能并不需要登录。可以进一步延伸到使用 deviceId,通过服务端下发列表。

  3. 检查安装来源。
    区分TestFlight/App Store/本地 build 几种安装方式。而苹果并没提供官方 API 来获取来源,作者提供了一个 hack 的方式,但可靠性有待确定,因为这种方式极大的依赖苹果的实现。

  4. 使用秘密的手势。
    使用某种复杂的手势来作为开关。但是如果有用户知道了这个手势,也可以调起调试功能。

    这种方式让我想起上家公司有关某个功能调试开关的实现,思路比较好玩。

    app 的某个页面,比如「设置 - 关于我们」(最好是无额外点击事件的页面)。把当前页面按照数字 0-9分为 10 个虚拟区域,类似拨号键盘排布。如下图所示:

image.png

而密码就是当前的手机时间,以 4 位数字表示,不足补 0。在页面上按照预设区域输入当前时间(当前实际上看不到任何分隔线的,估摸大致区域),即可打开调试开关。

  1. 使用秘密的 url scheme

    通过特定 url scheme 来唤起 app,以开启调试功能。但它有几个弊端:

    • 为了防止被破解,url 不能太简单,而且开发者需要记住该 url,调试不便。
    • 由于需要在浏览器中输入 url,那么意味着需要离开 app 进行操作,增加调试成本。
    • 如果有其他人意外知道了 url,同样也可以调试。

重头戏

下面重头戏来了,其方式是通过检测一个特殊的描述文件 Debug Profile 是否在机器上安装,来确定是否开启调试功能。

这种方式有如下好处:

但是也有其坏处:

原理

这种方式是基于 SecTrustEvaluate 方法来验证证书是否受信任。

使用 SecTrustEvaluate 来确定用户是否安装且信任了证书(通过安装描述文件),还是仅仅打包在 app 中未受信任的证书。

因此我们需要做的事情如下:

下面我们来一步步的操作。

1. 创建证书

a. 打开证书助理,选择创建证书颁发机构。

image.png

b. 填入名称和邮箱,反选 Make this CA the default,并勾选 Let me override defaults

image.png

c. 点击继续,修改有效期为 7300 天,即为 20 年。

image.png

d. 下一步,选择证书。这里我选择的是自己账号的证书。

image.png

e. 接下来,一直下一步,直至创建完成。

image.png

点击 Show CA Certificate 可以看到成功创建的证书。

image.png

2. 创建叶子证书

a. 打开证书助理,选择创建证书颁发机构

b. 填入名称和邮箱,反选 Make this CA the default,并勾选 Let me override defaults

注意这里跟第一步有所不同:

  1. Identity Type 选择 intermediate CA

  2. User Certificate 选择 custom,找到第一步中创建的 xx.certAuthorityConfig 文件。

    其目录在 ~/Library/Application Support/Certificate Authority/<your CA name>/<your CA name>.certAuthorityConfig

image.png

c. 修改有效期,同第一步中的 c
d. 选择证书,同第一步中的 d
e. 选择发行者。

这里选择第一步中创建的证书,我的证书名是 summer

image.png

f. 一路下一步,直至完成。

3. 导出叶子证书

Keychain Access 中,选中第 2 步创建的 leaf certificate ,右键导出为 cer 格式,并加入到自己的工程中。

4. 导出 CA 证书

Keychain Access 中,选中第 1 步创建的 root certificate ,右键导出为 cer 格式。不需要添加到工程。

5. 创建 Debug 描述文件

image.png

6. 编写检测代码

我将原文中的 SecTrustEvaluate 替换为了SecTrustEvaluateWithError,因为 SecTrustEvaluateiOS 13 上不再推荐使用。

SecTrustEvaluateWithError 的返回值为 bool。若为 true,则表示信任;若为 false,则表示不受信任。

- (BOOL)IsMobileConfigInstalled {
    NSString* certPath = [[NSBundle mainBundle] pathForResource:@"Certificates" ofType:@"cer"];
    if (certPath == nil) {
        return NO;
    }
    NSData* certData = [NSData dataWithContentsOfFile:certPath];
    if (certData == nil) {
        return NO;
    }
    
    SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef) certData);
    SecPolicyRef policy = SecPolicyCreateBasicX509();
    SecTrustRef trust;
    
    OSStatus err = SecTrustCreateWithCertificates((__bridge CFArrayRef) [NSArray arrayWithObject:(__bridge id)cert], policy, &trust);
    NSLog(@"Error Status?: %d", err);
    
    CFErrorRef error;
    BOOL result = SecTrustEvaluateWithError(trust, &error);
    NSLog(@"%d, %@", result, error);
    
    CFRelease(trust);
    CFRelease(policy);
    CFRelease(cert);
    
    return result;
}

7. 在需要调试的机器上安装描述文件

image.png image.png

同时 Apple Configurator 是这个状态,等安装完成会消失。

image.png

8. 运行工程

运行工程,会发现此时 SecTrustEvaluateWithError 返回的 resultYES

image.png

另外可以自行测试一下,如果移除了描述文件 Debug Profile,该结果则为 NO

上一篇 下一篇

猜你喜欢

热点阅读