美文网首页
iOS Release 版本开启调试功能

iOS Release 版本开启调试功能

作者: 微微笑的蜗牛 | 来源:发表于2020-05-03 20:12 被阅读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 是否在机器上安装,来确定是否开启调试功能。

这种方式有如下好处:

  • 如果想要调试就必须有描述文件,而普通用户无法获取。
  • 只需安装一次描述文件。
  • 一个描述文件 可以被多个 app 使用,不同优先级的功能可以使用不同的描述文件。
  • App Store 安装的 app 也可以使用,因为只需要有描述文件。
  • 不需要特殊的环境和用户。

但是也有其坏处:

  • 需要创建存储证书、 描述文件。
  • 需要根据检查证书信任结果来确定是否安装了描述文件,并且作者承认,检查方式有一点 hack
  • 需要将描述文件存起来,不能丢失。

原理

这种方式是基于 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 描述文件

  • 下载 Apple Configurator 2
  • 点击 File -> New Profile
    a. 在 General 中填入描述文件名称。
    b. 在 Certificates 一栏中选择在第 4 步中导出的 root.cer
    c. cmd+s 保存 Profile,取个合适的文件名,这里我将其命名为 custom-debug.mobileconfig
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. 在需要调试的机器上安装描述文件

  • 将手机用 USB 连上电脑,选择对应的设备。
  • 点击添加,选择 Profiles,再选择第 5 步中创建的描述文件。
image.png
  • 此时,在手机上会出现描述文件已经下载的提示。
image.png

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

image.png
  • 安装描述文件。打开 手机设置 -> 通用 -> 描述文件与设备管理,选择对应的描述文件进行安装。

8. 运行工程

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

image.png

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

相关文章

网友评论

      本文标题:iOS Release 版本开启调试功能

      本文链接:https://www.haomeiwen.com/subject/uosjghtx.html