ReactNative进阶(三十四):Jenkins 流水线 组包 iOS 应用包 ipa Archive 阶段报错error Multiple commands produce问题修复及思考(3)

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}

defaultConfig {
    applicationId "com.china.shq5785"
    minSdkVersion rootProject.ext.minSdkVersion
    targetSdkVersion rootProject.ext.targetSdkVersion
    versionCode 18072801
    versionName "2.2.5"
    multiDexEnabled true
    testBuildType System.getProperty('testBuildType', 'debug')
    // This will later be used to control the test apk build type
    testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
    ndk {
        //设置支持的SO库架构
        abiFilters "armeabi", "armeabi-v7a", "x86\_64" //, "arm64-v8a"
    }
     missingDimensionStrategy 'react-native-camera', 'general'
}
......

}


`ios` 在配置文件`ios/mrcs.xcodeproj/project.pbxproj`中,可查看到如下配置信息:



13B07F941A680F5B00A75B9A /* Debug / = {
isa = XCBuildConfiguration;
baseConfigurationReference = AA6AA411A14368FB4EEC0CD3 /
Pods-mrcs.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_IDENTITY = “iPhone Distribution”;
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 1;
DEAD_CODE_STRIPPING = NO;
DEVELOPMENT_TEAM = U4ALRF5A38;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
( i n h e r i t e d ) " , " (inherited)", " (inherited)","(PROJECT_DIR)/shq5785”,
( P R O J E C T _ D I R ) " , ) ; G C C P R E F I X H E A D E R = s h q 5785 / P r e f i x H e a d e r . p c h ; G C C W A R N A B O U T R E T U R N T Y P E = N O ; H E A D E R S E A R C H P A T H S = " (PROJECT\_DIR)", ); GCC_PREFIX_HEADER = shq5785/PrefixHeader.pch; GCC_WARN_ABOUT_RETURN_TYPE = NO; HEADER_SEARCH_PATHS = " (PROJECT_DIR)",);GCCPREFIXHEADER=shq5785/PrefixHeader.pch;GCCWARNABOUTRETURNTYPE=NO;HEADERSEARCHPATHS="(inherited)”;
INFOPLIST_FILE = shq5785/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
LD_RUNPATH_SEARCH_PATHS = “ ( i n h e r i t e d ) @ e x e c u t a b l e _ p a t h / F r a m e w o r k s " ; L I B R A R Y S E A R C H P A T H S = ( " (inherited) @executable\_path/Frameworks"; LIBRARY_SEARCH_PATHS = ( " (inherited)@executable_path/Frameworks";LIBRARYSEARCHPATHS=("(inherited)”,
( P R O J E C T _ D I R ) / s h q 5785 " , ) ; M A R K E T I N G V E R S I O N = 2.2.5 ; O T H E R C O D E S I G N F L A G S = " − − d e e p " ; O T H E R L D F L A G S = ( " (PROJECT\_DIR)/shq5785", ); MARKETING_VERSION = 2.2.5; OTHER_CODE_SIGN_FLAGS = "--deep"; OTHER_LDFLAGS = ( " (PROJECT_DIR)/shq5785",);MARKETINGVERSION=2.2.5;OTHERCODESIGNFLAGS="deep";OTHERLDFLAGS=("(inherited)”,
“-ObjC”,
“-lc++”,
);
PRODUCT_BUNDLE_IDENTIFIER = com.china.shq5785;
PRODUCT_NAME = shq5785;
PROVISIONING_PROFILE_SPECIFIER = “1111”;
SWIFT_OBJC_BRIDGING_HEADER = “$(PRODUCT_MODULE_NAME)/shq5785-Bridging-Header.h”;
SWIFT_OPTIMIZATION_LEVEL = “-Onone”;
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = “apple-generic”;
};
name = Debug;
};


#### 4.2 ipa包生成过程


iOS 开发的最后一步就是进行 App 的打包和分发,这里分为两个步骤:


1. `Archive`:对 `Target` 进行**编译、归档**,生成 `.xcarchive` 文件。
2. `Export`:对 `.xcarchive` 归档文件进一步处理,生成不同渠道的 `.ipa` 包,进行分发。


当我们在 Xcode 菜单中选择 `Product -> Archive` 后,编译系统就会对当前的 Xcode 工程进行**分析、编译和打包**,最终生成目标 Target 的一个 Archive(**归档**),我们可以在 `Window -> Organizer -> Archives` 页面查看到所有缓存的历史归档信息:


![在这里插入图片描述](https://img-blog.csdnimg.cn/109bd99051a34dd890e95befc6d25182.png)  
 所谓的”**归档**“,就是对源码进行编译后,将此次编译生成的各种文件、资源、记录统一封装到一个地方,方便进行管理和回溯。


右键选择一个归档文件 archive,然后点击 Show in Finder,可以看到它在 Finder 中表示为一个 `.xcarchive` 后缀的文件。


![在这里插入图片描述](https://img-blog.csdnimg.cn/3a5e932b2f5d4db5bb368fd65b94d543.png)


这个 `.xcarchive` 文件包含了应用和它的符号表信息(`symbol information`)以及其它的相关资源,右键选择显示包内容,可以查看一个 Archive 归档中具体的文件结构:


![在这里插入图片描述](https://img-blog.csdnimg.cn/fc02ccc09c01409fa710a5e399f6f644.png)  
 其中每个文件夹的含义:


* **BCSymbolMaps**  
 Xcode 对 `BitCode` 符号表进行混淆(`Symbol Hiding`)后生成的对照表,和 `dSYM` 文件会一一对应。
* **dSYMs**  
 存储此次编译的符号表(`debug symbols`),用来符号化解析崩溃堆栈。
* **Products**  
 存储此次编译生成的的 App 包(`.app`)。


要注意的是这个包虽然包括了 App 运行需要的可执行文件以及其它资源,但是和最终用户下载的版本会有所不同。后续的 `export` 操作会对其进行进一步处理。


* **SCMBlueprint**  
 如果 Xcode 打开了版本管理(`Preferences -> Source Control -> Enable Source Control`),`SCMBlueprint` 文件夹会存储此次编译的版本控制信息,包括使用的 git 版本、仓库、分支等。


如果未来想要回溯此次编译的源码版本,可以从这个 `SCMBlueprint` 中找到必要的信息。


* **SwiftSupport**  
 如果在 Target 的 `Build Settings` 中打开了`ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES`,此次编译使用的 Swift 版本对应的标准库文件(`.dylib`)会被放到这个文件夹中。


发布 App 时,这些标准库也会被复制到 ipa bundle 中。


不过现在 Swift 的 ABI 已经稳定了,Xcode 10.2 及以后的版本打出来的包,在 iOS 12.2 及以后的系统的 app bundle 中不用再自带链接库了,节省了一定的体积。


了解 ipa 文件  
 **.ipa**(`iOS App Store Package`) 文件是最终被安装到 iPhone 上的应用格式,包含了运行 App 所必需的的签名、二进制包、资源等内容。


在 Organizer 中无论用什么方式 `export` 应用的安装包,最终生成的都是一个 `.ipa` 文件。


`.ipa` 本身是压缩包文件,如果要查看 ipa 中的内容,可以右键查看包内容,观察解压以后的包,主要包含以下内容:


![在这里插入图片描述](https://img-blog.csdnimg.cn/a288b2b384994577b04070a42fb05114.png)  
 App 的签名信息会被放到 `_CodeSignature` 文件夹中。


* **info.plist**  
 存储 App 主要信息的 plist 文件也会被一并打包到 ipa 中。
* **entitlements**  
 entitlement 直译成中文是“权益”、“权限”的意思。


当你在 `Capabilities` 中开启一些特定的权限时,Xcode 会自动给你生成一个`.entitlements` 文件,在这个文件中通过 xml 的格式将这些授权记录下来。


App 瘦身  
 要对 App 安装包体积进行压缩,首先要知道安装包占用的多少空间,这些空间由哪些部分组成,然后再进行针对性的优化。


查看最终用户安装包大小  
 实际上在 Xcode 本地 `archive` 出来的 app 包或者 `export` 出来的 ipa 包和最终用户下载的版本会有所不同(通常体积会大很多)。因为苹果可能会对 App 进行重新编译(如果上传了 `BitCode`),也会针对不同的设备型号、iOS 版本分发不同的资源(比如 2x、3x 的图片),最后还会对整个 `.ipa` 进行压缩,以减少从 App Store 下载时耗费的流量。


那么如何估算用户最终下载版本的包体积大小呢?其实在 iTunes Connect 页面可以直接查询到。


打开 iTunes Connect,选择 **我的App -> 活动 -> 所有构建版本**,然后选择一个要查看的版本:


![在这里插入图片描述](https://img-blog.csdnimg.cn/b8909ee523474de89702b2d9a174e34c.png)  
 找到 App Store 文件大小按钮:


![在这里插入图片描述](https://img-blog.csdnimg.cn/01e566a2337043faaaf1fa9cf1804cae.png)


在弹出的列表中,可以看到在最新版本的 iOS 系统下,不同设备下载的包体积大小:


![在这里插入图片描述](https://img-blog.csdnimg.cn/04f616c68a1e4ab981dec26256156e09.png)


列表中的两列:



> 
> * 下载大小:表示通过无线下载的压缩 App 大小;
> * 安装大小:安装后此 App 将在用户设备上占用的磁盘空间大小;
> 
> 
> 


**如何分析 App 包 Size?**  
 为了更直观地查看哪些资源占用了 App 安装包的体积,我们可以借助一些文件工具来分析解压后的 ipa 包,比如说 derlien


![在这里插入图片描述](https://img-blog.csdnimg.cn/b235e5cc02774c38ac74fd7eb1be8cc0.png)


可以很直观地看到各种不同类型文件所占的比例。


**检查未使用资源**  
 随着 App 的不断迭代,我们往往会无意间引入很多用不到的资源,或者一些资源的引用已经从代码中去除了,但是没有及时从 `bundle` 中删除,造成 App 包体积的浪费。


为了查找这些不再使用的资源,可以借助开源工具 [LSUnusedResources](https://bbs.csdn.net/topics/618166371) 来检测整个工程。



> 
> [LSUnusedResources](https://bbs.csdn.net/topics/618166371) 应用过程如下:
> 
> 
> 1. 可以从下面的地址下载 [LSUnusedResources](https://bbs.csdn.net/topics/618166371)  
>  源码,然后进行编译…
> 2. 将源码在Mac上运行,可以看到如下界面:![在这里插入图片描述](https://img-blog.csdnimg.cn/f4d4ca080efe4f62a56768679542dfac.png)在Project> Path目录中,点击Browse…选择要检测工程的根目录,然后点击Search,开始进行检索…,你可以在下方的日志窗中看到检测结果>
> 3. 检测完成后,可以点击Export将此日志导出,然后开始进行清理工作.切勿不管三七二十一直接开删,毕竟是机器检测,不可完全信赖。
> 
> 
> 


针对一些特殊情况,比如代码中使用例如 `[UIImage imageNamed:[NSString stringWithFormat:@"icon_tag_%d", index]]` 的方式引用资源,LSUnusedResources 也支持使用正则表达式来模糊匹配。


**压缩图片**  
 图片文件是安装包中最常见的资源了,常常会占有相当一部分比例,未压缩的图片体积往往相当大,通过一些工具压缩图片资源,节省空间:


* 无损压缩:ImageOptim
* 有损压缩:tinypng


**使用 Asset Catalogs 存储资源**  
 相比于直接将图片拖入工程目录的方式,使用 Asset Catalogs 会更节省体积。Asset Catalogs 会用一个高度优化的特殊格式来存所有图片,对 png 图片也会进行最大化的压缩。


Xcode 工程模板会自动生成一个 `Assets.xcassets` 文件,我们也可以按需创建另外的 `.xcassets`,最终在 ipa 包中,这些 xcassets 都会被压缩到 `Assets.car` 文件中,一定程度上也保证了安全性。


![640?wx_fmt=png](https://img-blog.csdnimg.cn/54ac6a73cb5e4aefa068bf50935b91c4.png)


除了图片资源外,Asset Catalogs 也可以存储文本、Data 甚至 AR、apple TV 相关的资源,非常全能,所以比较好的实践就是:


能用 Asset Catalogs 管理的资源,尽量使用 Asset Catalogs 来管理


**分析 LinkMap 文件**  
 上面提到,App 包占用空间中很大一部分比例是最终编译生成的可执行文件(`MACH-O`),可执行文件的大小不仅和代码体积有关,也受**编译器版本、编译选项、链接库、目标架构**等影响。


可以通过分析编译时产生的 LinkMap 来了解 `MACH-O` 文件的组成部分。


要找到对应的 LinkMap,首先在 `Xcode Target -> Build Settings -> Write Link Map File` 设置为 YES,然后在 `Target -> Build Settings -> Path to Link Map File` 选项中设置好 LinkMap 的生成地址(一般用 build 文件夹中的默认地址就好了),archive 成功后,我们就可以在对应地址找到该次编译的 LinkMap 了:


![640?wx_fmt=png](https://img-blog.csdnimg.cn/d4c9abfee44446679cba6180fa3327c2.png)


LinkMap 记录了编译时的链接信息,用来描述可执行文件的构造成分,包括代码段`__TEXT` 和数据段 `__DATA` 的分布情况:


![640?wx_fmt=png](https://img-blog.csdnimg.cn/cb462b343d8b4747abc582e1f4e5fd4d.png)  
 网上有很多脚本可以对 LinkMap 进行分析统计,比如:


**可视化工具**


* js脚本
* 命令行工具


**ES6**

*   列举常用的ES6特性:

*   箭头函数需要注意哪些地方?

*   let、const、var

*   拓展:var方式定义的变量有什么样的bug?

*   Set数据结构

*   拓展:数组去重的方法

*   箭头函数this的指向。

*   手写ES6 class继承。

![](https://img-blog.csdnimg.cn/img_convert/aac1740e50faadb9a6a7a5b97f9ccba8.png)

**[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

**微信小程序**

*   简单描述一下微信小程序的相关文件类型?

*   你是怎么封装微信小程序的数据请求?

*   有哪些参数传值的方法?

*   你使用过哪些方法,来提高微信小程序的应用速度?

*   小程序和原生App哪个好?

*   简述微信小程序原理?

*   分析微信小程序的优劣势

*   怎么解决小程序的异步请求问题?

![](https://img-blog.csdnimg.cn/img_convert/60b1dbe5c76e264468aa993416a9a031.png)
  • 23
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值