|
1 | 1 | # iOS Setup Guide |
2 | 2 |
|
3 | | -## SPM Framework Embedding Required |
| 3 | +## SPM Framework Signing (Physical Devices) |
4 | 4 |
|
5 | | -QuickCrypto uses Swift Package Manager (SPM) dependencies that must be manually embedded in your app bundle: |
| 5 | +QuickCrypto uses OpenSSL via Swift Package Manager (SPM). On **physical iOS devices**, SPM frameworks require additional configuration to be properly embedded and code-signed in your app bundle. |
6 | 6 |
|
7 | | -- **OpenSSL 3.6+** (required) - For ML-DSA post-quantum cryptography support |
8 | | -- **Sodium** (optional) - For XSalsa20 cipher support via libsodium (when `SODIUM_ENABLED=1`) |
| 7 | +> **Simulator builds work without this configuration.** This is only required for physical device deployment. |
9 | 8 |
|
10 | | -### Why is this needed? |
| 9 | +### Quick Setup |
11 | 10 |
|
12 | | -CocoaPods doesn't automatically embed SPM frameworks into the final app bundle. Without this configuration, you'll encounter runtime errors: |
| 11 | +Add to your `ios/Podfile`: |
13 | 12 |
|
14 | | -``` |
15 | | -dyld: Library not loaded: @rpath/OpenSSL.framework/OpenSSL |
| 13 | +```ruby |
| 14 | +# At the top of your Podfile |
| 15 | +require_relative '../node_modules/react-native-quick-crypto/scripts/quickcrypto_spm_fix' |
| 16 | + |
| 17 | +target 'YourAppName' do |
| 18 | + # ... your pods ... |
| 19 | + |
| 20 | + post_install do |installer| |
| 21 | + react_native_post_install(installer) # if you have this |
| 22 | + |
| 23 | + # Fix QuickCrypto SPM framework signing for physical devices |
| 24 | + quickcrypto_fix_spm_signing(installer) |
| 25 | + end |
| 26 | +end |
16 | 27 | ``` |
17 | 28 |
|
18 | | -This is a temporary limitation of mixing CocoaPods + SPM. It will be resolved when React Native fully migrates to SPM (expected 2026). |
| 29 | +Then run: |
19 | 30 |
|
20 | | -## Configuration |
| 31 | +```bash |
| 32 | +cd ios && pod install |
| 33 | +``` |
| 34 | + |
| 35 | +### Why is this needed? |
21 | 36 |
|
22 | | -Add the following to your `ios/Podfile` inside the `post_install` hook: |
| 37 | +When you try to install on a physical device without this fix, you'll see: |
23 | 38 |
|
24 | | -```ruby |
25 | | -post_install do |installer| |
26 | | - # ... your existing post_install code (react_native_post_install, etc.) ... |
27 | | - |
28 | | - # Embed SPM frameworks from QuickCrypto |
29 | | - main_project_path = File.join(installer.sandbox.root.parent, 'YourAppName.xcodeproj') |
30 | | - main_project = Xcodeproj::Project.open(main_project_path) |
31 | | - app_target = main_project.targets.find { |t| t.name == 'YourAppName' } |
32 | | - |
33 | | - if app_target |
34 | | - embed_phase_name = 'Embed SPM Frameworks (QuickCrypto)' |
35 | | - existing_phase = app_target.shell_script_build_phases.find { |p| p.name == embed_phase_name } |
36 | | - |
37 | | - unless existing_phase |
38 | | - phase = app_target.new_shell_script_build_phase(embed_phase_name) |
39 | | - phase.shell_script = <<~SCRIPT |
40 | | - mkdir -p "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}" |
41 | | -
|
42 | | - # Embed OpenSSL.framework (required for ML-DSA) |
43 | | - if [ -d "${BUILT_PRODUCTS_DIR}/OpenSSL.framework" ]; then |
44 | | - rsync -av --delete "${BUILT_PRODUCTS_DIR}/OpenSSL.framework" "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/" |
45 | | - if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" ]; then |
46 | | - /usr/bin/codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/OpenSSL.framework" |
47 | | - fi |
48 | | - fi |
49 | | -
|
50 | | - # Embed Sodium.framework (optional, if SODIUM_ENABLED=1) |
51 | | - if [ -d "${BUILT_PRODUCTS_DIR}/Sodium.framework" ]; then |
52 | | - rsync -av --delete "${BUILT_PRODUCTS_DIR}/Sodium.framework" "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/" |
53 | | - if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" ]; then |
54 | | - /usr/bin/codesign --force --sign "${EXPANDED_CODE_SIGN_IDENTITY}" --preserve-metadata=identifier,entitlements "${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sodium.framework" |
55 | | - fi |
56 | | - fi |
57 | | - SCRIPT |
58 | | - |
59 | | - # Insert before the CocoaPods embed frameworks phase |
60 | | - embed_pods_phase = app_target.shell_script_build_phases.find { |p| p.name == '[CP] Embed Pods Frameworks' } |
61 | | - if embed_pods_phase |
62 | | - app_target.build_phases.move(phase, app_target.build_phases.index(embed_pods_phase)) |
63 | | - end |
64 | | - |
65 | | - main_project.save |
66 | | - end |
67 | | - end |
68 | | -end |
69 | 39 | ``` |
| 40 | +Failed to verify code signature of .../OpenSSL.framework : 0xe8008015 |
| 41 | +``` |
| 42 | + |
| 43 | +This happens because: |
| 44 | +1. OpenSSL is distributed as a pre-built, pre-signed xcframework via SPM |
| 45 | +2. CocoaPods' `spm_dependency` adds it to the Pods project but doesn't embed it in your app |
| 46 | +3. The framework must be re-signed with your app's code signing identity |
| 47 | + |
| 48 | +This is a known limitation of mixing CocoaPods + SPM. See [issue #857](https://github.com/margelo/react-native-quick-crypto/issues/857). |
70 | 49 |
|
71 | | -**Important:** Replace `YourAppName` with your actual Xcode target name (usually matches your app name). |
| 50 | +### Multiple Targets |
72 | 51 |
|
73 | | -## Example |
| 52 | +If you have multiple app targets, specify which one: |
74 | 53 |
|
75 | | -See the [example app's Podfile](../../example/ios/Podfile) for a complete working reference. |
| 54 | +```ruby |
| 55 | +quickcrypto_fix_spm_signing(installer, app_target_name: 'YourSpecificTarget') |
| 56 | +``` |
76 | 57 |
|
77 | 58 | ## Enabling libsodium (Optional) |
78 | 59 |
|
79 | | -To enable XSalsa20 cipher support, set the environment variable before installing pods: |
| 60 | +For XSalsa20 cipher support, set the environment variable before your target: |
80 | 61 |
|
81 | 62 | ```ruby |
82 | | -# At the top of your Podfile |
83 | 63 | ENV['SODIUM_ENABLED'] = '1' |
84 | | -``` |
85 | | - |
86 | | -Then run: |
87 | 64 |
|
88 | | -```bash |
89 | | -cd ios && pod install |
| 65 | +target 'YourAppName' do |
| 66 | + # ... |
| 67 | +end |
90 | 68 | ``` |
91 | 69 |
|
92 | 70 | ## Troubleshooting |
93 | 71 |
|
94 | | -### Error: "Library not loaded: @rpath/OpenSSL.framework/OpenSSL" |
| 72 | +### Error: `0xe8008015` on physical device |
95 | 73 |
|
96 | | -This means the SPM frameworks aren't being embedded. Verify: |
| 74 | +This is the code signing error. Make sure you've added `quickcrypto_fix_spm_signing(installer)` to your Podfile's `post_install` hook and run `pod install`. |
97 | 75 |
|
98 | | -1. The `post_install` hook is properly configured in your Podfile |
99 | | -2. You're using `use_frameworks! :linkage => :dynamic` (required for SPM dependencies) |
100 | | -3. Run `cd ios && pod install` after modifying the Podfile |
101 | | -4. Clean build folder in Xcode (Cmd+Shift+K) and rebuild |
| 76 | +### Error: "Library not loaded: @rpath/OpenSSL.framework" |
102 | 77 |
|
103 | | -### Dynamic Frameworks Required |
| 78 | +Same fix - the `quickcrypto_fix_spm_signing` function handles both embedding and signing. |
104 | 79 |
|
105 | | -QuickCrypto requires dynamic framework linking due to SPM dependencies. Add this to your Podfile: |
| 80 | +### Build still fails after adding the fix |
106 | 81 |
|
107 | | -```ruby |
108 | | -use_frameworks! :linkage => :dynamic |
109 | | -``` |
| 82 | +1. Clean build: `Cmd+Shift+K` in Xcode |
| 83 | +2. Delete derived data: `rm -rf ~/Library/Developer/Xcode/DerivedData` |
| 84 | +3. Run `pod install` again |
| 85 | +4. Rebuild |
| 86 | + |
| 87 | +### "Could not find main Xcode project" warning |
| 88 | + |
| 89 | +The helper script couldn't find your `.xcodeproj` file. Use the `app_target_name` parameter or check that your project structure is standard. |
| 90 | + |
| 91 | +## The SPM Situation |
110 | 92 |
|
111 | | -## Future |
| 93 | +Yes, this is unfortunate. CocoaPods is being deprecated, SPM is supposed to be the future, but SPM's handling of binary frameworks with CocoaPods is broken. The `spm_dependency` bridge in React Native doesn't properly handle framework embedding and code signing. |
112 | 94 |
|
113 | | -When React Native completes its migration to Swift Package Manager (expected 2026), this manual embedding step will no longer be necessary. SPM packages will be properly integrated by default. |
| 95 | +This workaround will be unnecessary when React Native fully migrates to SPM (timeline unclear). |
0 commit comments