React Native开发iOS实战录

文章目录

    • 背景
    • 环境准备
      • 基础工具:xcode安装
      • 主要工具
      • 安装CocoaPods
      • 基本步骤
        • 采用Expo go运行
        • iOS模拟器运行
        • 安装在真机上测试
        • 发布到苹果商店
        • 原生模块与编译链接问题
          • 静态库和 Framework
          • use_frameworks!和use_modular_headers!
          • 常见问题
            • ruby3在macOS上编译失败
            • import of module ‘glog.glog.log_severity’ appears within namespace ‘google’
            • yarn网络问题
            • pod安装失败
            • unable to open settings file
            • xcode运行报Undefined symbol: _OBJC_CLASS_$_RCTImageLoader
            • Unable to resolve "missing-asset-registry-path" from
            • Undefined symbols for architecture XXX
            • 相关链接

              背景

              准备将之前的一个React Native应用部署到iOS上,于是开始了探索之旅。

              一下子就牵扯出了Ruby,CocoaPods,Expo等新事物,虽然我很早以前搞过Ruby,但早就放弃了,没想到今天还得重新装一把ruby, gems。

              React Native本身代码不难写,但打包部署似乎比开发程序还麻烦,当然打包部署是一锤子买卖。

              涉及工具:Ruby, Node, CocoaPods, npx, yarn, react native, expo

              环境准备

              调查研究表明,搭建各种软件环境占据程序员四分之一的时间。采用RN for iOS时,安装pod和编译pod是一大险滩,你在package.json中引入了多少依赖,差不多就要安装多少个pod。各种版本的差异,会导致形形色色的编译问题。

              基础工具:xcode安装

              brew -v
              xcodebuild -version
              xcrun swift -version
              swift --version
              

              主要工具

              先安装nvm,再安装node。我安装的是v20.11.0。

              npx是一个由Node.js官方提供的用于快速执行npm包中的可执行文件的工具。它可以帮助我们在不全局安装某些包的情况下,直接运行该包提供的命令行工具。npx会在执行时,检查本地项目中是否安装了对应的依赖,如果没有安装则会自动下载安装,并执行命令。如果本地已经存在该依赖,则直接执行命令。

              查看几个主要工具的版本:

              ## expo版本
              npx expo -v
              0.17.5
              ## create-expo-app版本
              create-expo-app -v
              2.1.1
              ## react-native版本
              react-native -v
              react-native-cli: 2.0.1
              react-native: 0.73.4
              ## pod 版本
              pod --version
              1.15.2
              

              安装CocoaPods

              CocoaPods是开发iOS项目的库管理工具。它拥有超过55,000个库,并在超过300万个应用程序中使用。通过CocoaPods可以帮助我们优雅地扩展项目,便捷的导入第三方开源库。

              cocoapod 是用ruby写的。在工程文件里执行 pod init 会生成Podfile文件,通过Podfile文件来下载依赖的库。所以少不了和ruby打交道。

              CocoaPods is a dependency manager for Swift and Objective-C Cocoa projects. It has over 98 thousand libraries and is used in over 3 million apps. CocoaPods can help you scale your projects elegantly.

              安装步骤:

              ## 先安装rvm和ruby
              brew install gnupg 
              gpg --keyserver hkp://pgp.mit.edu --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
              curl -sSL https://get.rvm.io | bash -s stable --ruby
              ## 查看rvm版本:
              rvm -v
              ## 查看现在使用RVM管理的Ruby版本:
              which rvm
              ##列出可供RVM使用的Ruby版本:
              rvm list
              ## 列出可安装的版本:
              rvm list known
              

              设置代理:

              git config --global http.proxy socks5://127.0.0.1:1080
              git config --global https.proxy socks5://127.0.0.1:1080
              sudo killall -HUP mDNSResponder  ## 刷新本地环境
              #取消代理的方式
              git config --global --unset http.proxy
              git config --global --unset http.https://github.com.proxy
              

              这样,执行pod install 和 pod update速度都会变快

              更换gem源和pod源:

              gem sources l ## 查看当前源
              gem sources --remove https://rubygems.org/
              gem sources -a https://mirrors.aliyun.com/rubygems/  ## 添加新阿里巴巴gem镜像
              ## 在Podfile里添加
              source 'https://mirrors.tuna.tsinghua.edu.cn/git/CocoaPods/Specs.git'
              

              基本步骤

              基本命令:

              create-expo-app <项目名称> ## 创建一个expo项目
              npx expo prebuild ## 创建iOS或android目录
              npx expo run:ios ## 创建目录,且编译
              npx expo run:ios --configuration Release
              

              修改Podfile, 增加下面行:

              use_frameworks!
              #use_modular_headers!
              pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec', :modular_headers => false
              pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => false
              #pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec', :modular_headers => false
              pod 'RCT-Folly', :podspec => '../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec', :modular_headers => false
              #pod 'RCT-Folly.default-Fabric-Futures', :podspec => '', :modular_headers => false
              pod 'boost', :podspec => '../node_modules/react-native/third-party-podspecs/boost.podspec', :modular_headers => false
              # pod 'React-utils', :podspec => '../node_modules/react-native/ReactCommon/react/utils/React-utils.podspec', :modular_headers => false
              # pod 'React-Mapbuffer', :podspec => '../node_modules/react-native/ReactCommon/React-Mapbuffer.podspec', :modular_headers => false
              

              采用Expo go运行

              如果采用Expo go托管测试,则运行yarn expo start,然后用iPhone的扫码器扫一下二维码,就可以安装在真机上运行了。这种方式仅用于开发阶段。

              iOS模拟器运行

              执行npx expo run:ios后正常运行起来后的样子:

              这种方式可以用于应用的开发测试。

              也可以通过xcode启动模拟器,如果没有编译错误,就能启动模拟器,运行你的app:

              安装在真机上测试

              如果要部署到真机上测试,可以用xcode打开ios目录下的xcworkspace工程文件,然后点运行即可。设备里选你的真机,就会跑在真机上。这种方式只需要有Apple ID并创建测试证书即可。

              发布到苹果商店

              采用Expo提供的EAS工具就可以发布到App Store。基本步骤如下:

              npm install -g eas-cli ## 安装eas命令行工具
              eas build:configure ## 配置你的项目
              eas build --platform ios ## 构建你的app
              eas submit -p ios  ## 提交到Apple store
              

              原生模块与编译链接问题

              静态库和 Framework

              • *.a 的静态库类似于编译好的机械代码,源代码和库代码都被整合到单个可执行文件中,所以它会和设备架构绑定,并且不包含资源文件比如图片;
              • Framework 支持将动态库、头文件和资源文件封装到一起的一种格式,其中动态库的简单理解是:不会像静态库一样被整合到一起,而是在运行或者运行时动态链接;

                use_frameworks!和use_modular_headers!

                use_frameworks!告诉 CocoaPods 你想使用 Framework 而不是静态库,而默认由于 Swift 不支持静态库,因此有一开始 Swift 必须使用 Framework 的限制。

                use_modular_headers! ,它主要是将 pods 转为 Modular,因为 Modular 是可以直接在 Swift中 import ,所以不需要再经过 bridging-header 的桥接。

                但是开启 use_modular_headers! 之后,会使用更严格的 header 搜索路径,开启后 pod 会启用更严格的搜索路径和生成模块映射,历史项目可能会出现重复引用等问题,因为在一些老项目里 CocoaPods 是利用Header Search Paths 来完成引入编译,当然使用 use_modular_headers!可以提高加载性能和减少体积。

                当LocalPods中的模块使用Swift

                1、必须将主项目的podfile改成use_frameworks! :linkage => :static。但是有时执行调用模块内方法会出现unrecognized selector,需要command+k清除之后重新编译。改成dynamic还是每次修改视图显示都要重新编译,否则不生效。

                2、本地模块的xx.podspec文件中的s.public_header_files = 'Classes/Public//*.h’这个参数设置好像只能用于.h文件,如果改成“‘Classes/Public//*’”导入了Public目录下.m或.swift文件会有问题。Swift文件能不能被模块外访问可以用open/public访问控制修饰,默认访问控制是internal只能模块内使用这些类,改成open可以被模块外继承重写,public可以被模块外使用。

                3、在模块内部的OC文件里不能使用“#import “RCLiveModule(模块名)-Swift.h””,在主项目中可以,因为是use_frameworks!,如果去掉这句则变成模块内部可以使用而在主项目中不可以。而且那些需要被OC访问的类需要有一个父类,并且自定义方法要加上@objc才会自动生成OC方法。

                use_frameworks!

                1、use_frameworks!使用框架,默认是动态链接,到了cocoapods1.9之后可以指定动态链接(use_frameworks! :linkage => :dynamic)还是静态链接(use_frameworks! :linkage => :static)。

                2、OC默认不使用use_frameworks!,Swift只能使用use_frameworks!。

                常见问题

                ruby3在macOS上编译失败

                一般多为openssl版本问题导致,重新安装一下:

                brew reinstall openssl@3
                rvm install ruby-3.2.2 --reconfigure --enable-yjit --with-openssl-dir=$(brew --prefix openssl@3)
                

                import of module ‘glog.glog.log_severity’ appears within namespace ‘google’

                pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec', :modular_headers => false
                pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => false
                pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec', :modular_headers => false
                

                yarn网络问题

                yarn config delete proxy
                npm config rm proxy
                npm config rm https-proxy
                yarn config set registry https://registry.npm.taobao.org
                yarn install --network-timeout 6000 ## 毫秒
                

                pod安装失败

                The Swift pod `ExpoModulesCore` depends upon `glog`, which does not define modules. To opt into those targets generating module maps (which is necessary to import them from Swift when building as static libraries), you may set `use_modular_headers!` globally in your Podfile, or specify `:modular_headers => true` for particular dependencies.
                

                根据上面提示,修改Pofile文件,添加use_modular_headers!,或者为某个依赖指定:modular_headers => true

                use_modular_headers!
                pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec', :modular_headers => false
                pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec', :modular_headers => true
                pod 'RCT-Folly', :podspec => '../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec', :modular_headers => true
                pod 'boost', :podspec => '../node_modules/react-native/third-party-podspecs/boost.podspec', :modular_headers => false
                

                unable to open settings file

                Showing Recent Messages
                /Users/XX/Desktop/XX/Pods/Target Support Files/Pods-XX/Pods-XX.debug.xcconfig: unable to open file (in target "XX" in project "XX")
                

                解决方法:

                sudo gem install cocoapods --pre
                或者   sudo gem install -n /usr/local/bin cocoapods --pre
                再:
                pod install
                pod update(pod install 不行再执行)
                

                xcode运行报Undefined symbol: OBJC_CLASS$_RCTImageLoader

                TODO

                Unable to resolve “missing-asset-registry-path” from

                启动metro服务器后,运行app,报错:

                Unable to resolve "missing-asset-registry-path" from  "node_modules/@expo/vector-icons/build/vendor/react-native-vector-icons/Fonts/AntDesign.ttf"
                

                升级Expo到最新版就解决了,metro水太深。

                Undefined symbols for architecture XXX

                完整错误示例:

                 Linking   react-native-screens Pods/RNScreens » RNScreens
                ❌  Undefined symbols for architecture x86_64
                ┌─ Symbol: _OBJC_CLASS_$_RCTImageLoader
                └─ Referenced from: objc-class-ref in RNSScreenStackHeaderConfig.o
                

                在xcode里手动链接。

                相关链接

                • The New Expo CLI
                • cocoapods
                • swift下载
                • swiftenv
                • 2023年最新苹果AppleiOS开发证书申请创建App详细图文流程