zixflow-reactnative 1.1.3 → 1.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +631 -261
- package/android/build.gradle +18 -1
- package/android/consumer-rules.pro +3 -2
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/zixflow/reactnative/sdk/NativeZixflowModule.kt +40 -5
- package/android/src/main/java/com/zixflow/reactnative/sdk/ZixflowReactNativePackage.kt +25 -1
- package/android/src/main/java/com/zixflow/reactnative/sdk/constant/Keys.kt +19 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/geofence/NativeGeofenceModule.kt +65 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/liveactivities/NativeLiveActivitiesModule.kt +310 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginapp/NativeMessagingInAppModule.kt +150 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginapp/ReactInboxEventListener.kt +99 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/NotificationInboxBellViewManager.kt +38 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/NotificationInboxViewManager.kt +30 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactComposeHostView.kt +96 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactNotificationInboxBellView.kt +48 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messaginginbox/ReactNotificationInboxView.kt +17 -0
- package/android/src/main/java/com/zixflow/reactnative/sdk/messagingpush/NativeMessagingPushModule.kt +11 -1
- package/android/src/main/res/values/zixflow_config.xml +1 -1
- package/android/zixflow-core.gradle +17 -7
- package/docs/cocoapods-deployment-target-normalization.md +139 -0
- package/ios/cocoapods_deployment_target.rb +432 -0
- package/ios/wrappers/NativeZixflow.mm +37 -0
- package/ios/wrappers/NativeZixflow.swift +135 -1
- package/ios/wrappers/ZixflowReactNativeDeepLinkRequestStore.swift +123 -0
- package/ios/wrappers/ZixflowReactNativeDeepLinkRouter.swift +312 -0
- package/ios/wrappers/geofence/NativeGeofence.mm +46 -0
- package/ios/wrappers/geofence/NativeGeofence.swift +27 -0
- package/ios/wrappers/inapp/NativeMessagingInApp.mm +22 -0
- package/ios/wrappers/inapp/NativeMessagingInApp.swift +90 -0
- package/ios/wrappers/inbox/InboxHostContainment.swift +40 -0
- package/ios/wrappers/inbox/RCTNotificationInboxBellNative.h +12 -0
- package/ios/wrappers/inbox/RCTNotificationInboxBellNative.mm +98 -0
- package/ios/wrappers/inbox/RCTNotificationInboxViewNative.h +12 -0
- package/ios/wrappers/inbox/RCTNotificationInboxViewNative.mm +78 -0
- package/ios/wrappers/inbox/ReactInboxEventListener.swift +76 -0
- package/ios/wrappers/inbox/ReactNotificationInboxBellView.h +22 -0
- package/ios/wrappers/inbox/ReactNotificationInboxBellView.swift +109 -0
- package/ios/wrappers/inbox/ReactNotificationInboxView.h +22 -0
- package/ios/wrappers/inbox/ReactNotificationInboxView.swift +69 -0
- package/ios/wrappers/liveactivities/NativeLiveActivities.mm +83 -0
- package/ios/wrappers/liveactivities/NativeLiveActivities.swift +390 -0
- package/ios/wrappers/location/NativeLocation.swift +7 -5
- package/ios/wrappers/utils/ZixflowConstants.swift +4 -0
- package/ios/wrappers/zixflow_reactnative.h +6 -0
- package/lib/commonjs/components/NotificationInboxBellView.js +49 -0
- package/lib/commonjs/components/NotificationInboxBellView.js.map +1 -0
- package/lib/commonjs/components/NotificationInboxView.js +36 -0
- package/lib/commonjs/components/NotificationInboxView.js.map +1 -0
- package/lib/commonjs/components/index.js +14 -0
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/index.js +81 -4
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/notification-inbox.js +1 -0
- package/lib/commonjs/notification-inbox.js.map +1 -1
- package/lib/commonjs/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
- package/lib/commonjs/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
- package/lib/commonjs/specs/modules/NativeZixflow.js.map +1 -1
- package/lib/commonjs/specs/modules/NativeZixflowGeofence.js +15 -0
- package/lib/commonjs/specs/modules/NativeZixflowGeofence.js.map +1 -0
- package/lib/commonjs/specs/modules/NativeZixflowLiveActivities.js +23 -0
- package/lib/commonjs/specs/modules/NativeZixflowLiveActivities.js.map +1 -0
- package/lib/commonjs/specs/modules/NativeZixflowMessagingInApp.js +3 -1
- package/lib/commonjs/specs/modules/NativeZixflowMessagingInApp.js.map +1 -1
- package/lib/commonjs/specs/modules/NativeZixflowMessagingPush.js +3 -1
- package/lib/commonjs/specs/modules/NativeZixflowMessagingPush.js.map +1 -1
- package/lib/commonjs/types/data-pipelines.js +13 -1
- package/lib/commonjs/types/data-pipelines.js.map +1 -1
- package/lib/commonjs/types/in-app.js +24 -1
- package/lib/commonjs/types/in-app.js.map +1 -1
- package/lib/commonjs/types/inbox.js +79 -0
- package/lib/commonjs/types/inbox.js.map +1 -0
- package/lib/commonjs/types/index.js +22 -0
- package/lib/commonjs/types/index.js.map +1 -1
- package/lib/commonjs/types/live-activities.js +85 -0
- package/lib/commonjs/types/live-activities.js.map +1 -0
- package/lib/commonjs/utils/param-validation.js +76 -1
- package/lib/commonjs/utils/param-validation.js.map +1 -1
- package/lib/commonjs/zixflow-cdp.js +99 -1
- package/lib/commonjs/zixflow-cdp.js.map +1 -1
- package/lib/commonjs/zixflow-geofence.js +55 -0
- package/lib/commonjs/zixflow-geofence.js.map +1 -0
- package/lib/commonjs/zixflow-inapp.js +120 -0
- package/lib/commonjs/zixflow-inapp.js.map +1 -1
- package/lib/commonjs/zixflow-liveactivities.js +85 -0
- package/lib/commonjs/zixflow-liveactivities.js.map +1 -0
- package/lib/module/components/NotificationInboxBellView.js +44 -0
- package/lib/module/components/NotificationInboxBellView.js.map +1 -0
- package/lib/module/components/NotificationInboxView.js +31 -0
- package/lib/module/components/NotificationInboxView.js.map +1 -0
- package/lib/module/components/index.js +5 -0
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/index.js +8 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/notification-inbox.js +1 -1
- package/lib/module/notification-inbox.js.map +1 -1
- package/lib/module/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
- package/lib/module/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
- package/lib/module/specs/modules/NativeZixflow.js.map +1 -1
- package/lib/module/specs/modules/NativeZixflowGeofence.js +13 -0
- package/lib/module/specs/modules/NativeZixflowGeofence.js.map +1 -0
- package/lib/module/specs/modules/NativeZixflowLiveActivities.js +21 -0
- package/lib/module/specs/modules/NativeZixflowLiveActivities.js.map +1 -0
- package/lib/module/specs/modules/NativeZixflowMessagingInApp.js +3 -1
- package/lib/module/specs/modules/NativeZixflowMessagingInApp.js.map +1 -1
- package/lib/module/specs/modules/NativeZixflowMessagingPush.js +3 -1
- package/lib/module/specs/modules/NativeZixflowMessagingPush.js.map +1 -1
- package/lib/module/types/data-pipelines.js +13 -0
- package/lib/module/types/data-pipelines.js.map +1 -1
- package/lib/module/types/in-app.js +24 -0
- package/lib/module/types/in-app.js.map +1 -1
- package/lib/module/types/inbox.js +75 -0
- package/lib/module/types/inbox.js.map +1 -0
- package/lib/module/types/index.js +2 -0
- package/lib/module/types/index.js.map +1 -1
- package/lib/module/types/live-activities.js +88 -0
- package/lib/module/types/live-activities.js.map +1 -0
- package/lib/module/utils/param-validation.js +76 -1
- package/lib/module/utils/param-validation.js.map +1 -1
- package/lib/module/zixflow-cdp.js +99 -1
- package/lib/module/zixflow-cdp.js.map +1 -1
- package/lib/module/zixflow-geofence.js +50 -0
- package/lib/module/zixflow-geofence.js.map +1 -0
- package/lib/module/zixflow-inapp.js +99 -1
- package/lib/module/zixflow-inapp.js.map +1 -1
- package/lib/module/zixflow-liveactivities.js +80 -0
- package/lib/module/zixflow-liveactivities.js.map +1 -0
- package/lib/typescript/commonjs/components/NotificationInboxBellView.d.ts +39 -0
- package/lib/typescript/commonjs/components/NotificationInboxBellView.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/NotificationInboxView.d.ts +25 -0
- package/lib/typescript/commonjs/components/NotificationInboxView.d.ts.map +1 -0
- package/lib/typescript/commonjs/components/index.d.ts +4 -0
- package/lib/typescript/commonjs/components/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +8 -1
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/notification-inbox.d.ts +5 -0
- package/lib/typescript/commonjs/notification-inbox.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/components/NotificationInboxBellNativeComponent.d.ts +13 -0
- package/lib/typescript/commonjs/specs/components/NotificationInboxBellNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/components/NotificationInboxViewNativeComponent.d.ts +12 -0
- package/lib/typescript/commonjs/specs/components/NotificationInboxViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflow.d.ts +6 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflow.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowGeofence.d.ts +13 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowGeofence.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowLiveActivities.d.ts +31 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowLiveActivities.d.ts.map +1 -0
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingInApp.d.ts +5 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingInApp.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingPush.d.ts +1 -1
- package/lib/typescript/commonjs/specs/modules/NativeZixflowMessagingPush.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/data-pipelines.d.ts +53 -1
- package/lib/typescript/commonjs/types/data-pipelines.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/in-app.d.ts +22 -0
- package/lib/typescript/commonjs/types/in-app.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/inbox.d.ts +97 -0
- package/lib/typescript/commonjs/types/inbox.d.ts.map +1 -0
- package/lib/typescript/commonjs/types/index.d.ts +2 -0
- package/lib/typescript/commonjs/types/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/types/live-activities.d.ts +161 -0
- package/lib/typescript/commonjs/types/live-activities.d.ts.map +1 -0
- package/lib/typescript/commonjs/utils/param-validation.d.ts +7 -0
- package/lib/typescript/commonjs/utils/param-validation.d.ts.map +1 -1
- package/lib/typescript/commonjs/zixflow-cdp.d.ts +38 -0
- package/lib/typescript/commonjs/zixflow-cdp.d.ts.map +1 -1
- package/lib/typescript/commonjs/zixflow-geofence.d.ts +36 -0
- package/lib/typescript/commonjs/zixflow-geofence.d.ts.map +1 -0
- package/lib/typescript/commonjs/zixflow-inapp.d.ts +36 -2
- package/lib/typescript/commonjs/zixflow-inapp.d.ts.map +1 -1
- package/lib/typescript/commonjs/zixflow-liveactivities.d.ts +66 -0
- package/lib/typescript/commonjs/zixflow-liveactivities.d.ts.map +1 -0
- package/lib/typescript/module/components/NotificationInboxBellView.d.ts +39 -0
- package/lib/typescript/module/components/NotificationInboxBellView.d.ts.map +1 -0
- package/lib/typescript/module/components/NotificationInboxView.d.ts +25 -0
- package/lib/typescript/module/components/NotificationInboxView.d.ts.map +1 -0
- package/lib/typescript/module/components/index.d.ts +4 -0
- package/lib/typescript/module/components/index.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +8 -1
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/notification-inbox.d.ts +5 -0
- package/lib/typescript/module/notification-inbox.d.ts.map +1 -1
- package/lib/typescript/module/specs/components/NotificationInboxBellNativeComponent.d.ts +13 -0
- package/lib/typescript/module/specs/components/NotificationInboxBellNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/specs/components/NotificationInboxViewNativeComponent.d.ts +12 -0
- package/lib/typescript/module/specs/components/NotificationInboxViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/module/specs/modules/NativeZixflow.d.ts +6 -1
- package/lib/typescript/module/specs/modules/NativeZixflow.d.ts.map +1 -1
- package/lib/typescript/module/specs/modules/NativeZixflowGeofence.d.ts +13 -0
- package/lib/typescript/module/specs/modules/NativeZixflowGeofence.d.ts.map +1 -0
- package/lib/typescript/module/specs/modules/NativeZixflowLiveActivities.d.ts +31 -0
- package/lib/typescript/module/specs/modules/NativeZixflowLiveActivities.d.ts.map +1 -0
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingInApp.d.ts +5 -1
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingInApp.d.ts.map +1 -1
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingPush.d.ts +1 -1
- package/lib/typescript/module/specs/modules/NativeZixflowMessagingPush.d.ts.map +1 -1
- package/lib/typescript/module/types/data-pipelines.d.ts +53 -1
- package/lib/typescript/module/types/data-pipelines.d.ts.map +1 -1
- package/lib/typescript/module/types/in-app.d.ts +22 -0
- package/lib/typescript/module/types/in-app.d.ts.map +1 -1
- package/lib/typescript/module/types/inbox.d.ts +97 -0
- package/lib/typescript/module/types/inbox.d.ts.map +1 -0
- package/lib/typescript/module/types/index.d.ts +2 -0
- package/lib/typescript/module/types/index.d.ts.map +1 -1
- package/lib/typescript/module/types/live-activities.d.ts +161 -0
- package/lib/typescript/module/types/live-activities.d.ts.map +1 -0
- package/lib/typescript/module/utils/param-validation.d.ts +7 -0
- package/lib/typescript/module/utils/param-validation.d.ts.map +1 -1
- package/lib/typescript/module/zixflow-cdp.d.ts +38 -0
- package/lib/typescript/module/zixflow-cdp.d.ts.map +1 -1
- package/lib/typescript/module/zixflow-geofence.d.ts +36 -0
- package/lib/typescript/module/zixflow-geofence.d.ts.map +1 -0
- package/lib/typescript/module/zixflow-inapp.d.ts +36 -2
- package/lib/typescript/module/zixflow-inapp.d.ts.map +1 -1
- package/lib/typescript/module/zixflow-liveactivities.d.ts +66 -0
- package/lib/typescript/module/zixflow-liveactivities.d.ts.map +1 -0
- package/package.json +11 -2
- package/src/components/NotificationInboxBellView.tsx +55 -0
- package/src/components/NotificationInboxView.tsx +30 -0
- package/src/components/index.ts +6 -0
- package/src/index.ts +8 -3
- package/src/notification-inbox.ts +1 -1
- package/src/specs/components/NotificationInboxBellNativeComponent.ts +24 -0
- package/src/specs/components/NotificationInboxViewNativeComponent.ts +22 -0
- package/src/specs/modules/NativeZixflow.ts +9 -1
- package/src/specs/modules/NativeZixflowGeofence.ts +14 -0
- package/src/specs/modules/NativeZixflowLiveActivities.ts +39 -0
- package/src/specs/modules/NativeZixflowMessagingInApp.ts +12 -1
- package/src/specs/modules/NativeZixflowMessagingPush.ts +3 -1
- package/src/types/data-pipelines.ts +54 -1
- package/src/types/in-app.ts +23 -0
- package/src/types/inbox.ts +110 -0
- package/src/types/index.ts +2 -0
- package/src/types/live-activities.ts +170 -0
- package/src/utils/param-validation.ts +103 -0
- package/src/zixflow-cdp.ts +117 -1
- package/src/zixflow-geofence.ts +56 -0
- package/src/zixflow-inapp.ts +125 -2
- package/src/zixflow-liveactivities.ts +86 -0
- package/zixflow-reactnative-richpush.podspec +4 -1
- package/zixflow-reactnative.podspec +26 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# CocoaPods deployment-target normalization
|
|
2
|
+
|
|
3
|
+
Xcode validates the deployment target of every generated CocoaPods target, including dependency,
|
|
4
|
+
aggregate, privacy-manifest, and resource-bundle targets. Xcode 27 rejects targets below the build
|
|
5
|
+
range supported by its iOS SDK even when the dependency itself is source-compatible with your app.
|
|
6
|
+
|
|
7
|
+
The `zixflow-reactnative` package includes an opt-in Podfile helper. It raises low or missing
|
|
8
|
+
generated settings to the greater of React Native's current minimum and iOS 15.0. For React Native
|
|
9
|
+
0.83 that value is iOS 15.1. It also covers integrated application, Notification Service
|
|
10
|
+
Extension, and widget targets, while preserving higher numeric deployment targets. When a target
|
|
11
|
+
setting is absent, the helper resolves its target xcconfig and then the same-named project build
|
|
12
|
+
configuration, preserving a higher inherited app or extension floor. The helper changes local build
|
|
13
|
+
settings in the generated Pods project and CocoaPods-integrated app or extension projects. It does
|
|
14
|
+
not rewrite a podspec or change runtime API availability.
|
|
15
|
+
|
|
16
|
+
The package owns and tests this copy of the helper because customer Podfiles must be able to load it
|
|
17
|
+
from the installed npm package. When its behavior changes, update the helper, tests, and guidance
|
|
18
|
+
together. It does not depend on a cross-repository source lock or require wrapper copies to remain
|
|
19
|
+
byte-identical.
|
|
20
|
+
|
|
21
|
+
Zixflow deliberately continues to publish native SDKs that support iOS versions below 15. A
|
|
22
|
+
podspec can therefore correctly declare that lower library minimum even when React Native or the
|
|
23
|
+
application consuming it requires a newer iOS version. CocoaPods carries deployment metadata from
|
|
24
|
+
Zixflow and third-party podspecs into generated build targets, but Xcode 27 no longer accepts
|
|
25
|
+
targets below the iOS SDK's supported build range. Raising every published podspec to iOS 15 would
|
|
26
|
+
unnecessarily drop older applications and would not control metadata from transitive
|
|
27
|
+
dependencies. The helper instead aligns the generated targets with the host application's chosen
|
|
28
|
+
minimum while leaving the packages' published runtime compatibility unchanged.
|
|
29
|
+
This is the supported integration policy for a React Native application that has moved its own
|
|
30
|
+
minimum to the required iOS floor.
|
|
31
|
+
|
|
32
|
+
> [!WARNING]
|
|
33
|
+
> This is an opt-in build migration. Integrated app and extension targets below the computed floor
|
|
34
|
+
> are raised to that floor. With React Native 0.83, shipping the resulting iOS 15.1 application
|
|
35
|
+
> means users on iOS 15.0 and earlier cannot install subsequent app updates. Adopt the helper only
|
|
36
|
+
> when your product has intentionally moved its application and extension deployment targets.
|
|
37
|
+
|
|
38
|
+
Resolve the helper through Node so hoisted and monorepo installations work, then call it after
|
|
39
|
+
`react_native_post_install` in the one existing `post_install` block:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
def node_resolve(script)
|
|
43
|
+
Pod::Executable.execute_command('node', ['-p',
|
|
44
|
+
"require.resolve('#{script}', {paths: [process.argv[1]]})",
|
|
45
|
+
__dir__
|
|
46
|
+
]).strip
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
customer_io_package_root = File.dirname(node_resolve('zixflow-reactnative/package.json'))
|
|
50
|
+
require File.join(customer_io_package_root, 'ios', 'cocoapods_deployment_target')
|
|
51
|
+
|
|
52
|
+
customer_io_minimum_ios_version = Zixflow::CocoaPodsDeploymentTarget.maximum(
|
|
53
|
+
min_ios_version_supported,
|
|
54
|
+
'15.0'
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
post_install do |installer|
|
|
58
|
+
react_native_post_install(
|
|
59
|
+
installer,
|
|
60
|
+
config[:reactNativePath],
|
|
61
|
+
:mac_catalyst_enabled => false
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
Zixflow::CocoaPodsDeploymentTarget.normalize!(
|
|
65
|
+
installer,
|
|
66
|
+
minimum_ios_version: customer_io_minimum_ios_version
|
|
67
|
+
)
|
|
68
|
+
end
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Remove the generated `ios/Pods` directory and run `pod install` again. When a target build-setting
|
|
72
|
+
key is absent, the helper resolves the target xcconfig and matching project configuration before
|
|
73
|
+
adding an override. A present target key is authoritative, so lower-precedence xcconfig and project
|
|
74
|
+
values are not inspected. This matches Xcode's treatment of an explicitly empty target value: it
|
|
75
|
+
is missing and must be normalized, rather than inherited from a lower-precedence value. For each
|
|
76
|
+
change, the helper prints a stable project, target, and configuration line with the original
|
|
77
|
+
effective value and final value. It fails the install if the selected effective value is
|
|
78
|
+
non-numeric, such as `$(CUSTOM_IOS_FLOOR)`, because the generated-project audit cannot prove its
|
|
79
|
+
resolved value. A non-numeric value at a lower precedence does not fail when an explicit target
|
|
80
|
+
setting already determines the effective value.
|
|
81
|
+
SDK-, architecture-, or configuration-qualified keys such as
|
|
82
|
+
`IPHONEOS_DEPLOYMENT_TARGET[sdk=iphoneos*]` also fail before mutation at the selected precedence.
|
|
83
|
+
Xcode can choose a qualified key over an unconditional value, so adding a numeric override would
|
|
84
|
+
not prove the effective floor and could lower a higher conditional project setting. Replace the
|
|
85
|
+
selected conditional matrix with one numeric, unconditional deployment target before rerunning the
|
|
86
|
+
helper.
|
|
87
|
+
|
|
88
|
+
If the helper reports a non-numeric selected value, use the project, target, and configuration in
|
|
89
|
+
the error to locate the authoritative `IPHONEOS_DEPLOYMENT_TARGET`. Replace the macro or inherited
|
|
90
|
+
expression at that precedence with its intended numeric version, then run `pod install` again. For
|
|
91
|
+
a generated Pods target, make that override durably in the Podfile's `post_install` hook before
|
|
92
|
+
calling `Zixflow::CocoaPodsDeploymentTarget.normalize!`, or correct the podspec that supplies the
|
|
93
|
+
expression; do not edit the generated project because the next install replaces it. Do not skip
|
|
94
|
+
that target: continuing with an unresolved expression would leave the generated project outside
|
|
95
|
+
the deterministic audit. The helper validates every selected value before changing any project,
|
|
96
|
+
so this failure does not leave a partially normalized installation.
|
|
97
|
+
|
|
98
|
+
If an error says a selected xcconfig cannot be read or parsed, repair or remove the reported base
|
|
99
|
+
configuration file reference for the reported project, target, and configuration. Lower-precedence
|
|
100
|
+
xcconfigs are not parsed when the target build-setting key is present. Run the helper in the
|
|
101
|
+
CocoaPods Ruby environment so the public `Xcodeproj::Config` parser is available.
|
|
102
|
+
Synchronized-group xcconfig references are not resolved by that public parser; if the helper
|
|
103
|
+
reports one, replace it with a standard xcconfig file reference, then run `pod install` again.
|
|
104
|
+
These cases fail before any project mutation.
|
|
105
|
+
|
|
106
|
+
## When the helper is no longer needed
|
|
107
|
+
|
|
108
|
+
Keep the helper while a supported dependency graph can validly include deployment metadata below
|
|
109
|
+
the host application's minimum. This is expected while Zixflow supports older iOS versions or
|
|
110
|
+
supported third-party pods continue to declare lower minimums. A `platform` declaration in the
|
|
111
|
+
application's Podfile alone does not guarantee that every generated target uses the same value.
|
|
112
|
+
|
|
113
|
+
The helper becomes unnecessary only when a clean install without it proves that every
|
|
114
|
+
target/configuration in every supported React Native and push-provider graph declares an effective
|
|
115
|
+
numeric deployment target at or above the host application's minimum. That state would normally
|
|
116
|
+
follow an intentional platform-support change across the SDK, wrappers, and relevant dependencies;
|
|
117
|
+
it is not a prerequisite for adopting Xcode 27. Keep the audit in CI after removing the helper so
|
|
118
|
+
a later dependency update cannot silently reintroduce a lower target.
|
|
119
|
+
|
|
120
|
+
Repository contributors also have a deterministic CI audit under `scripts/` that prints the target,
|
|
121
|
+
matching project, and effective value for every generated target/configuration pair in stable
|
|
122
|
+
order. That audit script is not part of the published npm package. It examines every target in each
|
|
123
|
+
passed project, including non-integrated targets that the normalizer intentionally does not change;
|
|
124
|
+
set those targets to the host minimum explicitly. Pass the `Pods` directory so the audit discovers
|
|
125
|
+
every `.xcodeproj` directly under it, including CocoaPods multi-project output, while ignoring
|
|
126
|
+
unrelated example projects vendored inside downloaded pod sources. It fails if a supplied path is
|
|
127
|
+
missing or contains no projects.
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
cd example
|
|
131
|
+
bundle exec ruby ../scripts/audit_cocoapods_deployment_targets.rb \
|
|
132
|
+
--minimum 15.1 \
|
|
133
|
+
ios/Pods \
|
|
134
|
+
ios/SampleApp.xcodeproj
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Keep this audit next to the React Native simulator build and unsigned generic-device archive.
|
|
138
|
+
Passing those checks does not prove real-device push delivery, signed archive export, or App Store
|
|
139
|
+
submission.
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This packaged copy is owned by zixflow-reactnative and covered by its local test suite.
|
|
4
|
+
|
|
5
|
+
require "rubygems/version"
|
|
6
|
+
|
|
7
|
+
module Zixflow
|
|
8
|
+
# Normalizes every CocoaPods-generated target and every integrated application or extension
|
|
9
|
+
# target to a numeric iOS deployment target that the selected Xcode toolchain supports.
|
|
10
|
+
module CocoaPodsDeploymentTarget
|
|
11
|
+
BUILD_SETTING = "IPHONEOS_DEPLOYMENT_TARGET"
|
|
12
|
+
VERSION_PATTERN = /\A\d+(?:\.\d+){0,2}\z/.freeze
|
|
13
|
+
|
|
14
|
+
Record = Struct.new(
|
|
15
|
+
:project,
|
|
16
|
+
:target,
|
|
17
|
+
:configuration,
|
|
18
|
+
:original_effective,
|
|
19
|
+
:target_configuration_value,
|
|
20
|
+
:project_value,
|
|
21
|
+
:current,
|
|
22
|
+
:changed,
|
|
23
|
+
:configuration_object,
|
|
24
|
+
keyword_init: true
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
class AuditError < StandardError; end
|
|
28
|
+
|
|
29
|
+
module_function
|
|
30
|
+
|
|
31
|
+
# Raises low effective deployment settings to +minimum_ios_version+. A missing target setting
|
|
32
|
+
# resolves through its xcconfig and then the same-named project configuration. Numeric effective
|
|
33
|
+
# settings above the minimum are preserved. A selected non-numeric effective setting fails
|
|
34
|
+
# closed because its resolved value cannot be audited deterministically from the project.
|
|
35
|
+
def normalize!(installer, minimum_ios_version:, io: $stdout)
|
|
36
|
+
minimum = parse_version!(minimum_ios_version, context: "minimum iOS version")
|
|
37
|
+
targets = installer_targets(installer)
|
|
38
|
+
records = records_for(targets)
|
|
39
|
+
ensure_records!(records)
|
|
40
|
+
validate_numeric_settings!(records)
|
|
41
|
+
|
|
42
|
+
records = records.map do |record|
|
|
43
|
+
normalize_record!(record, minimum)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
audit_records!(records, minimum)
|
|
47
|
+
save_integrated_user_projects!(installer, records)
|
|
48
|
+
write_changes(io, records)
|
|
49
|
+
write_summary(io, records, minimum)
|
|
50
|
+
records
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Audits an installer without modifying it. This is useful from a second post-install check.
|
|
54
|
+
def audit!(installer, minimum_ios_version:, io: $stdout)
|
|
55
|
+
minimum = parse_version!(minimum_ios_version, context: "minimum iOS version")
|
|
56
|
+
records = records_for(installer_targets(installer))
|
|
57
|
+
ensure_records!(records)
|
|
58
|
+
|
|
59
|
+
audit_records!(records, minimum)
|
|
60
|
+
write_summary(io, records, minimum)
|
|
61
|
+
records
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Audits projects loaded by Xcodeproj. The caller owns loading the projects so this helper does
|
|
65
|
+
# not add a runtime dependency on Xcodeproj to the normal Podfile integration path.
|
|
66
|
+
def audit_projects!(projects, minimum_ios_version:, io: $stdout)
|
|
67
|
+
minimum = parse_version!(minimum_ios_version, context: "minimum iOS version")
|
|
68
|
+
targets = projects.flat_map { |project| project.targets }
|
|
69
|
+
records = records_for(targets)
|
|
70
|
+
ensure_records!(records)
|
|
71
|
+
|
|
72
|
+
audit_records!(records, minimum)
|
|
73
|
+
write_records(io, records, minimum)
|
|
74
|
+
records
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Returns the greater of two numeric iOS deployment targets. React Native integrations use
|
|
78
|
+
# this to preserve React Native's own floor when it is higher than Zixflow's floor.
|
|
79
|
+
def maximum(first, second)
|
|
80
|
+
first_version = parse_version!(first, context: "iOS version")
|
|
81
|
+
second_version = parse_version!(second, context: "iOS version")
|
|
82
|
+
[first_version, second_version].max.to_s
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def installer_targets(installer)
|
|
86
|
+
generated_projects = if installer.respond_to?(:generated_projects)
|
|
87
|
+
Array(installer.generated_projects).compact
|
|
88
|
+
else
|
|
89
|
+
[]
|
|
90
|
+
end
|
|
91
|
+
if generated_projects.empty? && installer.respond_to?(:pods_project)
|
|
92
|
+
generated_projects = [installer.pods_project].compact
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
pod_targets = generated_projects.flat_map { |project| project.targets }
|
|
96
|
+
user_targets = if installer.respond_to?(:aggregate_targets)
|
|
97
|
+
Array(installer.aggregate_targets).flat_map do |aggregate_target|
|
|
98
|
+
aggregate_target.respond_to?(:user_targets) ? Array(aggregate_target.user_targets) : []
|
|
99
|
+
end
|
|
100
|
+
else
|
|
101
|
+
[]
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
deduplicate_targets(pod_targets + user_targets)
|
|
105
|
+
end
|
|
106
|
+
private_class_method :installer_targets
|
|
107
|
+
|
|
108
|
+
def save_integrated_user_projects!(installer, records)
|
|
109
|
+
return unless installer.respond_to?(:aggregate_targets)
|
|
110
|
+
|
|
111
|
+
changed_project_paths = records.select(&:changed).map(&:project).uniq
|
|
112
|
+
return if changed_project_paths.empty?
|
|
113
|
+
|
|
114
|
+
projects = Array(installer.aggregate_targets).each_with_object([]) do |aggregate_target, result|
|
|
115
|
+
if aggregate_target.respond_to?(:user_project)
|
|
116
|
+
user_project = aggregate_target.user_project
|
|
117
|
+
result << user_project unless user_project.nil?
|
|
118
|
+
end
|
|
119
|
+
next unless aggregate_target.respond_to?(:user_targets)
|
|
120
|
+
|
|
121
|
+
Array(aggregate_target.user_targets).each do |target|
|
|
122
|
+
result << target.project if target.respond_to?(:project) && !target.project.nil?
|
|
123
|
+
end
|
|
124
|
+
end.compact
|
|
125
|
+
|
|
126
|
+
projects.select { |project| changed_project_paths.include?(project_path(project)) }
|
|
127
|
+
.uniq { |project| project_path(project) }
|
|
128
|
+
.each do |project|
|
|
129
|
+
unless project.respond_to?(:save)
|
|
130
|
+
raise AuditError, "Cannot save integrated user project #{project_path(project)}"
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
project.save
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
private_class_method :save_integrated_user_projects!
|
|
137
|
+
|
|
138
|
+
def deduplicate_targets(targets)
|
|
139
|
+
targets.each_with_object({}) do |target, unique|
|
|
140
|
+
project = target.respond_to?(:project) ? target.project : nil
|
|
141
|
+
project_key = project_path(project)
|
|
142
|
+
target_key = target.respond_to?(:uuid) ? target.uuid : target.object_id
|
|
143
|
+
unique[[project_key, target_key]] ||= target
|
|
144
|
+
end.values
|
|
145
|
+
end
|
|
146
|
+
private_class_method :deduplicate_targets
|
|
147
|
+
|
|
148
|
+
def normalize_record!(record, minimum)
|
|
149
|
+
current = record.current
|
|
150
|
+
current_version = current.nil? ? nil : parse_version!(current, context: record_context(record))
|
|
151
|
+
return record if current_version && current_version >= minimum
|
|
152
|
+
|
|
153
|
+
record.configuration_object.build_settings[BUILD_SETTING] = minimum.to_s
|
|
154
|
+
record.current = minimum.to_s
|
|
155
|
+
record.changed = true
|
|
156
|
+
record
|
|
157
|
+
end
|
|
158
|
+
private_class_method :normalize_record!
|
|
159
|
+
|
|
160
|
+
def records_for(targets)
|
|
161
|
+
targets.flat_map do |target|
|
|
162
|
+
project = target.respond_to?(:project) ? target.project : nil
|
|
163
|
+
target.build_configurations.map do |configuration|
|
|
164
|
+
context = configuration_context(project, target, configuration)
|
|
165
|
+
validate_no_conditional_settings!(configuration.build_settings, context: context)
|
|
166
|
+
target_setting_present = configuration.build_settings.key?(BUILD_SETTING)
|
|
167
|
+
target_value = normalized_setting(configuration.build_settings[BUILD_SETTING])
|
|
168
|
+
if target_setting_present
|
|
169
|
+
target_configuration_value = nil
|
|
170
|
+
project_value = nil
|
|
171
|
+
effective_value = target_value
|
|
172
|
+
else
|
|
173
|
+
target_configuration_present, target_configuration_value = configuration_file_setting(
|
|
174
|
+
configuration,
|
|
175
|
+
context: context
|
|
176
|
+
)
|
|
177
|
+
if target_configuration_present
|
|
178
|
+
project_value = nil
|
|
179
|
+
effective_value = target_configuration_value
|
|
180
|
+
else
|
|
181
|
+
project_configuration = matching_project_configuration(project, configuration.name)
|
|
182
|
+
project_value = effective_configuration_value(
|
|
183
|
+
project_configuration,
|
|
184
|
+
context: context
|
|
185
|
+
)
|
|
186
|
+
effective_value = project_value
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
Record.new(
|
|
190
|
+
project: project_path(project),
|
|
191
|
+
target: target.name.to_s,
|
|
192
|
+
configuration: configuration.name.to_s,
|
|
193
|
+
original_effective: effective_value,
|
|
194
|
+
target_configuration_value: target_configuration_value,
|
|
195
|
+
project_value: project_value,
|
|
196
|
+
current: effective_value,
|
|
197
|
+
changed: false,
|
|
198
|
+
configuration_object: configuration
|
|
199
|
+
)
|
|
200
|
+
end
|
|
201
|
+
end.sort_by { |record| [record.project, record.target, record.configuration] }
|
|
202
|
+
end
|
|
203
|
+
private_class_method :records_for
|
|
204
|
+
|
|
205
|
+
def effective_configuration_value(configuration, context:)
|
|
206
|
+
return nil if configuration.nil?
|
|
207
|
+
|
|
208
|
+
validate_no_conditional_settings!(configuration.build_settings, context: context)
|
|
209
|
+
|
|
210
|
+
if configuration.build_settings.key?(BUILD_SETTING)
|
|
211
|
+
return normalized_setting(configuration.build_settings[BUILD_SETTING])
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
_present, value = configuration_file_setting(configuration, context: context)
|
|
215
|
+
value
|
|
216
|
+
end
|
|
217
|
+
private_class_method :effective_configuration_value
|
|
218
|
+
|
|
219
|
+
def configuration_file_setting(configuration, context:)
|
|
220
|
+
synchronized_anchor = if configuration.respond_to?(:base_configuration_reference_anchor)
|
|
221
|
+
configuration.base_configuration_reference_anchor
|
|
222
|
+
end
|
|
223
|
+
synchronized_relative_path = if configuration.respond_to?(:base_configuration_reference_relative_path)
|
|
224
|
+
configuration.base_configuration_reference_relative_path
|
|
225
|
+
end
|
|
226
|
+
if synchronized_anchor || synchronized_relative_path
|
|
227
|
+
raise AuditError,
|
|
228
|
+
"#{context}: Cannot inspect synchronized-group xcconfig " \
|
|
229
|
+
"#{rendered_synchronized_path(synchronized_anchor, synchronized_relative_path)}. " \
|
|
230
|
+
"Use a standard xcconfig file reference before rerunning CocoaPods."
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
base_configuration_reference = if configuration.respond_to?(:base_configuration_reference)
|
|
234
|
+
configuration.base_configuration_reference
|
|
235
|
+
end
|
|
236
|
+
if base_configuration_reference
|
|
237
|
+
xcconfig_path = if base_configuration_reference.respond_to?(:real_path)
|
|
238
|
+
base_configuration_reference.real_path
|
|
239
|
+
end
|
|
240
|
+
unless xcconfig_path.respond_to?(:exist?) && xcconfig_path.exist? &&
|
|
241
|
+
xcconfig_path.respond_to?(:readable?) && xcconfig_path.readable?
|
|
242
|
+
rendered_path = xcconfig_path.nil? ? "(unresolved path)" : xcconfig_path.to_s
|
|
243
|
+
raise AuditError, "#{context}: Cannot read xcconfig #{rendered_path}"
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
unless defined?(::Xcodeproj::Config)
|
|
247
|
+
raise AuditError,
|
|
248
|
+
"#{context}: Cannot parse xcconfig #{xcconfig_path}; Xcodeproj::Config is unavailable"
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
begin
|
|
252
|
+
settings = ::Xcodeproj::Config.new(xcconfig_path).to_hash
|
|
253
|
+
rescue StandardError => error
|
|
254
|
+
raise AuditError,
|
|
255
|
+
"#{context}: Cannot parse xcconfig #{xcconfig_path}: " \
|
|
256
|
+
"#{error.class}: #{error.message}"
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
unless settings.respond_to?(:key?)
|
|
260
|
+
raise AuditError, "#{context}: Cannot inspect xcconfig #{xcconfig_path}"
|
|
261
|
+
end
|
|
262
|
+
validate_no_conditional_settings!(
|
|
263
|
+
settings,
|
|
264
|
+
context: "#{context}, xcconfig #{xcconfig_path}"
|
|
265
|
+
)
|
|
266
|
+
return [false, nil] unless settings.key?(BUILD_SETTING)
|
|
267
|
+
|
|
268
|
+
return [true, normalized_setting(settings[BUILD_SETTING])]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
[false, nil]
|
|
272
|
+
end
|
|
273
|
+
private_class_method :configuration_file_setting
|
|
274
|
+
|
|
275
|
+
def validate_no_conditional_settings!(settings, context:)
|
|
276
|
+
conditional_setting_pattern = /\A#{Regexp.escape(BUILD_SETTING)}[[:space:]]*\[/
|
|
277
|
+
conditional_keys = settings.keys.map(&:to_s).select do |key|
|
|
278
|
+
key.match?(conditional_setting_pattern)
|
|
279
|
+
end.sort
|
|
280
|
+
return if conditional_keys.empty?
|
|
281
|
+
|
|
282
|
+
raise AuditError,
|
|
283
|
+
"#{context} has conditional #{BUILD_SETTING} settings that cannot be audited deterministically: " \
|
|
284
|
+
"#{conditional_keys.join(', ')}. Replace them with one numeric, unconditional #{BUILD_SETTING} " \
|
|
285
|
+
"before running this helper."
|
|
286
|
+
end
|
|
287
|
+
private_class_method :validate_no_conditional_settings!
|
|
288
|
+
|
|
289
|
+
def rendered_synchronized_path(anchor, relative_path)
|
|
290
|
+
anchor_path = if anchor.respond_to?(:path)
|
|
291
|
+
anchor.path
|
|
292
|
+
elsif anchor.respond_to?(:display_name)
|
|
293
|
+
anchor.display_name
|
|
294
|
+
else
|
|
295
|
+
"(unknown anchor)"
|
|
296
|
+
end
|
|
297
|
+
[anchor_path, relative_path].compact.map(&:to_s).reject(&:empty?).join("/")
|
|
298
|
+
end
|
|
299
|
+
private_class_method :rendered_synchronized_path
|
|
300
|
+
|
|
301
|
+
def matching_project_configuration(project, configuration_name)
|
|
302
|
+
return nil if project.nil? || !project.respond_to?(:build_configurations)
|
|
303
|
+
|
|
304
|
+
Array(project.build_configurations).find do |configuration|
|
|
305
|
+
configuration.name.to_s == configuration_name.to_s
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
private_class_method :matching_project_configuration
|
|
309
|
+
|
|
310
|
+
def ensure_records!(records)
|
|
311
|
+
return unless records.empty?
|
|
312
|
+
|
|
313
|
+
raise AuditError, "CocoaPods iOS deployment-target audit found no target configurations"
|
|
314
|
+
end
|
|
315
|
+
private_class_method :ensure_records!
|
|
316
|
+
|
|
317
|
+
def validate_numeric_settings!(records)
|
|
318
|
+
records.each do |record|
|
|
319
|
+
parse_version!(record.current, context: record_context(record)) unless record.current.nil?
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
private_class_method :validate_numeric_settings!
|
|
323
|
+
|
|
324
|
+
def audit_records!(records, minimum)
|
|
325
|
+
violations = records.each_with_object([]) do |record, result|
|
|
326
|
+
current = record.current
|
|
327
|
+
if current.nil?
|
|
328
|
+
result << "#{record_context(record)} is missing #{BUILD_SETTING}"
|
|
329
|
+
else
|
|
330
|
+
begin
|
|
331
|
+
version = parse_version!(current, context: record_context(record))
|
|
332
|
+
if version < minimum
|
|
333
|
+
result << "#{record_context(record)} is #{current}, below #{minimum}"
|
|
334
|
+
end
|
|
335
|
+
rescue AuditError => error
|
|
336
|
+
result << error.message
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
return if violations.empty?
|
|
342
|
+
|
|
343
|
+
raise AuditError, "CocoaPods iOS deployment-target audit failed:\n- #{violations.join("\n- ")}"
|
|
344
|
+
end
|
|
345
|
+
private_class_method :audit_records!
|
|
346
|
+
|
|
347
|
+
def write_summary(io, records, minimum)
|
|
348
|
+
return if io.nil?
|
|
349
|
+
|
|
350
|
+
changed = records.count(&:changed)
|
|
351
|
+
io.puts(
|
|
352
|
+
"Zixflow CocoaPods deployment-target audit passed: " \
|
|
353
|
+
"#{records.length} target configurations at iOS #{minimum} or newer (#{changed} normalized)."
|
|
354
|
+
)
|
|
355
|
+
end
|
|
356
|
+
private_class_method :write_summary
|
|
357
|
+
|
|
358
|
+
def write_changes(io, records)
|
|
359
|
+
return if io.nil?
|
|
360
|
+
|
|
361
|
+
records.select(&:changed).each do |record|
|
|
362
|
+
original = record.original_effective.nil? ? "missing" : record.original_effective
|
|
363
|
+
io.puts(
|
|
364
|
+
"Zixflow CocoaPods deployment target normalized: " \
|
|
365
|
+
"#{record_context(record)}: #{original} -> #{record.current}"
|
|
366
|
+
)
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
private_class_method :write_changes
|
|
370
|
+
|
|
371
|
+
def write_records(io, records, minimum)
|
|
372
|
+
return if io.nil?
|
|
373
|
+
|
|
374
|
+
io.puts(
|
|
375
|
+
"project\ttarget\tconfiguration\ttarget_#{BUILD_SETTING}\t" \
|
|
376
|
+
"target_xcconfig_#{BUILD_SETTING}\t" \
|
|
377
|
+
"project_#{BUILD_SETTING}\teffective_#{BUILD_SETTING}"
|
|
378
|
+
)
|
|
379
|
+
records.each do |record|
|
|
380
|
+
target_value = normalized_setting(record.configuration_object.build_settings[BUILD_SETTING])
|
|
381
|
+
io.puts(
|
|
382
|
+
[
|
|
383
|
+
record.project,
|
|
384
|
+
record.target,
|
|
385
|
+
record.configuration,
|
|
386
|
+
target_value,
|
|
387
|
+
record.target_configuration_value,
|
|
388
|
+
record.project_value,
|
|
389
|
+
record.current
|
|
390
|
+
].join("\t")
|
|
391
|
+
)
|
|
392
|
+
end
|
|
393
|
+
write_summary(io, records, minimum)
|
|
394
|
+
end
|
|
395
|
+
private_class_method :write_records
|
|
396
|
+
|
|
397
|
+
def parse_version!(value, context:)
|
|
398
|
+
normalized = normalized_setting(value)
|
|
399
|
+
unless normalized&.match?(VERSION_PATTERN)
|
|
400
|
+
rendered = normalized.nil? ? "missing" : normalized.inspect
|
|
401
|
+
raise AuditError, "#{context} has non-numeric #{BUILD_SETTING}: #{rendered}"
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
Gem::Version.new(normalized)
|
|
405
|
+
end
|
|
406
|
+
private_class_method :parse_version!
|
|
407
|
+
|
|
408
|
+
def normalized_setting(value)
|
|
409
|
+
normalized = value.nil? ? nil : value.to_s.strip
|
|
410
|
+
normalized.nil? || normalized.empty? ? nil : normalized
|
|
411
|
+
end
|
|
412
|
+
private_class_method :normalized_setting
|
|
413
|
+
|
|
414
|
+
def record_context(record)
|
|
415
|
+
"#{record.project}: target #{record.target}, configuration #{record.configuration}"
|
|
416
|
+
end
|
|
417
|
+
private_class_method :record_context
|
|
418
|
+
|
|
419
|
+
def configuration_context(project, target, configuration)
|
|
420
|
+
"#{project_path(project)}: target #{target.name}, configuration #{configuration.name}"
|
|
421
|
+
end
|
|
422
|
+
private_class_method :configuration_context
|
|
423
|
+
|
|
424
|
+
def project_path(project)
|
|
425
|
+
return "unknown-project" if project.nil?
|
|
426
|
+
return project.path.to_s if project.respond_to?(:path) && project.path
|
|
427
|
+
|
|
428
|
+
project.to_s
|
|
429
|
+
end
|
|
430
|
+
private_class_method :project_path
|
|
431
|
+
end
|
|
432
|
+
end
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
#import "utils/RCTZixflowUtils.h"
|
|
2
2
|
#import <React/RCTBridgeModule.h>
|
|
3
|
+
#import <React/RCTInvalidating.h>
|
|
3
4
|
#import <RNZixflowSpec/RNZixflowSpec.h>
|
|
4
5
|
|
|
6
|
+
@protocol NativeZixflowBridge <NativeZixflowSpec, RCTInvalidating>
|
|
7
|
+
- (void)setEventEmitter:(id)emitter;
|
|
8
|
+
@end
|
|
9
|
+
|
|
5
10
|
// Objective-C wrapper for new architecture TurboModule implementation
|
|
6
11
|
@interface RCTNativeZixflow : NSObject <NativeZixflowSpec>
|
|
7
12
|
// Bridge to Swift implementation for cross-language compatibility
|
|
@@ -30,6 +35,7 @@ RCT_EXPORT_MODULE()
|
|
|
30
35
|
RCT_ASSERT_NOT_NIL(swiftClass, @"NativeZixflow Swift class", @"during runtime lookup");
|
|
31
36
|
_swiftBridge = [[swiftClass alloc] init];
|
|
32
37
|
[self assertBridgeAvailable:@"creating NativeZixflow Swift instance"];
|
|
38
|
+
[_swiftBridge setEventEmitter:self];
|
|
33
39
|
}
|
|
34
40
|
return self;
|
|
35
41
|
}
|
|
@@ -47,6 +53,37 @@ RCT_EXPORT_MODULE()
|
|
|
47
53
|
[_swiftBridge initialize:config args:args resolve:resolve reject:reject];
|
|
48
54
|
}
|
|
49
55
|
|
|
56
|
+
- (void)setDeepLinkRoutingReady {
|
|
57
|
+
[self assertBridgeAvailable:@"during setDeepLinkRoutingReady"];
|
|
58
|
+
[_swiftBridge setDeepLinkRoutingReady];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
- (void)registerDeepLinkHandler {
|
|
62
|
+
[self assertBridgeAvailable:@"during registerDeepLinkHandler"];
|
|
63
|
+
[_swiftBridge registerDeepLinkHandler];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
- (void)unregisterDeepLinkHandler {
|
|
67
|
+
[self assertBridgeAvailable:@"during unregisterDeepLinkHandler"];
|
|
68
|
+
[_swiftBridge unregisterDeepLinkHandler];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (void)acknowledgeDeepLink:(NSString *)id handled:(BOOL)handled {
|
|
72
|
+
[self assertBridgeAvailable:@"during acknowledgeDeepLink"];
|
|
73
|
+
[_swiftBridge acknowledgeDeepLink:id handled:handled];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
- (void)invalidate {
|
|
77
|
+
[self assertBridgeAvailable:@"during invalidate"];
|
|
78
|
+
[_swiftBridge invalidate];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Pins the Codegen event name at compile time. Keep this in sync with the TypeScript spec and the
|
|
82
|
+
// runtime selector in NativeZixflow.swift.
|
|
83
|
+
- (void)emitOnDeepLinkReceived:(NSDictionary *)value {
|
|
84
|
+
[super emitOnDeepLinkReceived:value];
|
|
85
|
+
}
|
|
86
|
+
|
|
50
87
|
- (void)identify:(NSDictionary *)params {
|
|
51
88
|
[self assertBridgeAvailable:@"during identify"];
|
|
52
89
|
[_swiftBridge identify:params];
|