「iOS」一次惨痛的 APP 上架经历

文章关键词:dSYM、#if/#ifdef/#ifndef、IAP(In App Purchase)、Analyze
复制代码

前言与项目背景(废话)

6 月 12 日 - 20 日,一言难尽心酸泪/大哭——提交 6 次,被拒6次,还有谁?/摊手数据库

项目从 5.2.0 接到手以后,到目前提审中的 6.0.4 以前,前先后后一共提交了 8 个版本,不管是新增功能仍是优化升级,都能顺利上架。而此次,从 6.0.4.0 开始提 TestFlight(审核经过),6.0.4.3 开始提交审核,如今已经 6.0.4.8 第六次提审了(目前还在审核中,前五次全军覆没)/摊手服务器

最关键的!此次是为了 618 而提交,影响心情不说,iOS 端的 618 活动受到耽误才是大事啊/大哭,但愿领导不要罚钱钱/可怜。app

「文章内包含未解决/未知问题,各位看官谨慎查看/摊手」ide

前三次被拒(关于dSYM)

前两次拒绝缘由

Guideline 2.1 - Performance - App Completeness
We were unable to review your app as it crashed on launch. We have attached detailed crash logs to help troubleshoot this issue.
复制代码

第三次拒绝缘由

Guideline 2.1 - Performance - App Completeness
We were unable to review your app as it still crashed on launch. We have attached detailed crash logs to help troubleshoot this issue.
复制代码

三次都在后面附上了 crash log 文件(看得出第三次审核团队也很无奈啊)测试

分析

仍是头一回遇到审核启动不了的状况,平常开发和测试中也并无出现过这个问题。优化

第一次被拒没注意看日志,觉得是打包打错了,检查一遍选项,肯定没问题便从新打包上传了,too young!ui

第二次被拒,分析日志能够看到启动时间过长触发 watchdog,程序被挂起(启动失败),按照日志中的 Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d 一番搜索,都是让符号化,但是并无 dSYM 文件,由于着急提交,便将程序启动-引导页-登陆页-首页流程捋了一遍,修改了几处疑似影响启动的地方,又打包从新提交,然而 too young!this

第三次被拒,心态爆炸心态爆炸心态爆炸!和原来作这个项目的同事沟通一番无果,怎么办也得提交啊,索性让这位同事打包吧!spa

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Termination Reason: Namespace SPRINGBOARD, Code 0x8badf00d
Termination Description: SPRINGBOARD, scene-create watchdog transgression: xxx.xxx.xxx exhausted real (wall clock) time allowance of 18.23 seconds | ProcessVisibility: Foreground | ProcessState: Running | WatchdogEvent: scene-create | WatchdogVisibility: Foreground | WatchdogCPUStatistics: ( | "Elapsed total CPU time (seconds): 27.760 (user 27.760, system 0.000), 46% CPU", | "Elapsed application CPU time (seconds): 1.037, 2% CPU" | )
Triggered by Thread:  0
复制代码

解决方案

这是在第四次被退回时才想到的方法,真的是脑子短路,被干懵了/摊手!.net

符号化 crash log 的方法再也不赘述,个人问题是打包文件里 dSYMs 文件夹是空的,并无 dSYM 文件/无奈。

看全部没有dSYM文件的文章上都是设置 Build Setting - Debug Information Format,即 Debug 下是 DWARFRelease 下是 DWARF with dSYM File,然而个人本来就是这个选项,Archive 仍旧没有生成 dSYM 文件/摊手。把 Debug 对应的 DWARF 改成 DWARF with dSYM File,从 DerivedData 却是能够找到 dSYM 文件,然并卵,uuid 对不起来仍是没法分析/无奈

由于项目比较久远,Build Setting 改动较大,而且不是对全部的设置选项都了解其根源,再加上上线紧迫,一个个去了解时间也不容许,索性新开一个 Demo 项目,默认设置下打包,打包是有 dSYM 文件的,接下来逐一对照项目去修改 DemoBuild Setting 并打包,直到没有 dSYM

最终定位到了相关设置选项:除了常规设置 Build Setting - Debug Information Format,同时要保证 Build Setting - Generate Debug SymbolsYES

这个方法解决了没有生成 dSYM 的问题,然而以后提交被拒却不是由于没法启动了/无奈。因为每次打包 uuid 都会变化,没有相对应的 uuidcrash log,没法符号化,因此以前没法启动的缘由如今也无从得知/摊手

特别提醒:若是不是特殊状况,不要为了缩小一点 .ipa 体积修改 Build Setting 中 Symbols 相关的设置,一旦审核出现了平时没法复现的问题,符号化 Log 解决起来会有迹可循。

TODO

何不对 Build Setting 来一次大扫除?

第四次被拒(关于 #if/#ifdef/#ifndef)

拒绝缘由

Guideline 2.1 - Performance - App Completeness
We discovered one or more bugs in your app when reviewed on iPad running iOS 12.3.1 on Wi-Fi.
App fails to connect to its server.
复制代码

分析

越有事越不能慌乱,你看,慌乱中忘记修改服务器地址就打包提交了,因此,此次还有脸分析吗?

没脸。

解决方案

虽然很没脸提,仍是给本身提了个醒:为何没有将服务器分开 DebugRelease? 不仅是服务器地址,还有一些逻辑或者日志打印区分开颇有必要!这也是开发中的小技巧了。

这里引入 #ifdef / #ifndef / #if / #elif / #else / #endif 的知识点,具体参考:#if 和 #ifdef的区别 或者 #if 和 #ifdef的区别(转载),再也不赘述。

第五次被拒(关于 IAP)

拒绝缘由

Guideline 2.3 - Performance - Accurate Metadata
We noticed that your app's metadata includes the following information, which is not relevant to the app's content and functionality:
Price of IAP is not matching the price of IAP batch.
复制代码

分析

WTF?内购商品价格显示不一致?这块是在接手以前的逻辑基础上新增了商品,新增以后也提交了几个版本了,忽然提出这个问题我也很懵😳。经过查看代码,以前的逻辑是在咱们本身的服务器获取商品列表,而咱们数据库中只保存了人民币的价格。看来仍是不够了解 Apple 审核规则/逃

解决方案

解决起来却是简单,在这里只是提醒你们别犯和我同样的错误/大笑。商品列表修改成从 Apple 服务器(Apple 服务器会根据设备登陆的 AppleID 所属的区域自动返回相应的价格)获取便可:

#import <StoreKit/StoreKit.h>

@interface XXXViewController () <SKProductsRequestDelegate>

- (void)productsRequestFromApple
{
    // appstoreconnect 商品 ids
    NSArray *ids = @[@"id", @"id", ...];
    // 根据商品 Ids 请求 appstore 的信息
    if ([SKPaymentQueue canMakePayments]) {
        NSSet *IDSet = [NSSet setWithArray:ids];
        SKProductsRequest *productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:IDSet];
        productsRequest.delegate = self;
        [productsRequest start];
    } else {
        NSLog(@"您已禁止应用内付费");
    }
}

#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
    // 产品信息
    NSArray *products = response.products;
    if (products.count == 0) {
        NSLog(@"未能获取产品信息");
    } else {
        for (SKProduct *product in products) {
            NSLog(@"localizedDescription: %@", product.localizedDescription);
            NSLog(@"localizedTitle: %@", product.localizedTitle);
            NSLog(@"price: %.2f", ([product.price floatValue]));
            NSLog(@"NSLocaleCurrencySymbol: %@", [product.priceLocale objectForKey:NSLocaleCurrencySymbol]);
            NSLog(@"NSLocaleCurrencyCode: %@", [product.priceLocale objectForKey:NSLocaleCurrencyCode]);
            NSLog(@"productIdentifier: %@", [product productIdentifier]);
        }
    }
}
复制代码

后面的付费流程再也不赘述。

第六次被拒(js 交互)

拒绝缘由

分析

解决方案

其余(关于 Analyze)

记得每次关键节点如打包等,shift + cmd + B 进行代码静态分析(Analyze)并处理,能够解决至关一部分潜在隐患。

后记

虽然程序里设置的活动结束时间 2019.06.20 23:59:59,但仍是但愿 21 日审核能顺利经过/无所谓

「完」

相关文章
相关标签/搜索