@use-voltra/ios-client 2.1.1 → 2.3.0
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 +61 -8
- package/Voltra.podspec +1 -0
- package/build/commonjs/dynamic-widget/api.js +15 -0
- package/build/commonjs/dynamic-widget/api.js.map +1 -0
- package/build/commonjs/events.js +23 -0
- package/build/commonjs/events.js.map +1 -1
- package/build/commonjs/index.js +74 -7
- package/build/commonjs/index.js.map +1 -1
- package/build/commonjs/live-activity/api.js +3 -1
- package/build/commonjs/live-activity/api.js.map +1 -1
- package/build/commonjs/live-activity/dynamic-api.js +173 -0
- package/build/commonjs/live-activity/dynamic-api.js.map +1 -0
- package/build/commonjs/native/NativeVoltra.js.map +1 -1
- package/build/commonjs/utils/enableDynamicLiveActivityHotReload.js +47 -0
- package/build/commonjs/utils/enableDynamicLiveActivityHotReload.js.map +1 -0
- package/build/commonjs/utils/enableWidgetHotReload.js +8 -11
- package/build/commonjs/utils/enableWidgetHotReload.js.map +1 -1
- package/build/commonjs/utils/useUpdateOnHMR.js +3 -7
- package/build/commonjs/utils/useUpdateOnHMR.js.map +1 -1
- package/build/commonjs/widgets/server-credentials.js +9 -0
- package/build/commonjs/widgets/server-credentials.js.map +1 -1
- package/build/commonjs/widgets/server-update.js +78 -0
- package/build/commonjs/widgets/server-update.js.map +1 -0
- package/build/module/dynamic-widget/api.js +10 -0
- package/build/module/dynamic-widget/api.js.map +1 -0
- package/build/module/events.js +23 -0
- package/build/module/events.js.map +1 -1
- package/build/module/index.js +4 -0
- package/build/module/index.js.map +1 -1
- package/build/module/live-activity/api.js +2 -2
- package/build/module/live-activity/api.js.map +1 -1
- package/build/module/live-activity/dynamic-api.js +167 -0
- package/build/module/live-activity/dynamic-api.js.map +1 -0
- package/build/module/native/NativeVoltra.js.map +1 -1
- package/build/module/utils/enableDynamicLiveActivityHotReload.js +43 -0
- package/build/module/utils/enableDynamicLiveActivityHotReload.js.map +1 -0
- package/build/module/utils/enableWidgetHotReload.js +9 -11
- package/build/module/utils/enableWidgetHotReload.js.map +1 -1
- package/build/module/utils/useUpdateOnHMR.js +3 -7
- package/build/module/utils/useUpdateOnHMR.js.map +1 -1
- package/build/module/widgets/server-credentials.js +9 -0
- package/build/module/widgets/server-credentials.js.map +1 -1
- package/build/module/widgets/server-update.js +72 -0
- package/build/module/widgets/server-update.js.map +1 -0
- package/build/typescript/commonjs/dynamic-widget/api.d.ts +8 -0
- package/build/typescript/commonjs/dynamic-widget/api.d.ts.map +1 -0
- package/build/typescript/commonjs/events.d.ts +7 -0
- package/build/typescript/commonjs/events.d.ts.map +1 -1
- package/build/typescript/commonjs/index.d.ts +4 -0
- package/build/typescript/commonjs/index.d.ts.map +1 -1
- package/build/typescript/commonjs/live-activity/api.d.ts +7 -0
- package/build/typescript/commonjs/live-activity/api.d.ts.map +1 -1
- package/build/typescript/commonjs/live-activity/dynamic-api.d.ts +54 -0
- package/build/typescript/commonjs/live-activity/dynamic-api.d.ts.map +1 -0
- package/build/typescript/commonjs/native/NativeVoltra.d.ts +21 -0
- package/build/typescript/commonjs/native/NativeVoltra.d.ts.map +1 -1
- package/build/typescript/commonjs/types.d.ts +1 -1
- package/build/typescript/commonjs/types.d.ts.map +1 -1
- package/build/typescript/commonjs/utils/enableDynamicLiveActivityHotReload.d.ts +15 -0
- package/build/typescript/commonjs/utils/enableDynamicLiveActivityHotReload.d.ts.map +1 -0
- package/build/typescript/commonjs/utils/enableWidgetHotReload.d.ts +5 -7
- package/build/typescript/commonjs/utils/enableWidgetHotReload.d.ts.map +1 -1
- package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts +0 -3
- package/build/typescript/commonjs/utils/useUpdateOnHMR.d.ts.map +1 -1
- package/build/typescript/commonjs/widgets/server-credentials.d.ts +8 -0
- package/build/typescript/commonjs/widgets/server-credentials.d.ts.map +1 -1
- package/build/typescript/commonjs/widgets/server-update.d.ts +64 -0
- package/build/typescript/commonjs/widgets/server-update.d.ts.map +1 -0
- package/build/typescript/module/dynamic-widget/api.d.ts +8 -0
- package/build/typescript/module/dynamic-widget/api.d.ts.map +1 -0
- package/build/typescript/module/events.d.ts +7 -0
- package/build/typescript/module/events.d.ts.map +1 -1
- package/build/typescript/module/index.d.ts +4 -0
- package/build/typescript/module/index.d.ts.map +1 -1
- package/build/typescript/module/live-activity/api.d.ts +7 -0
- package/build/typescript/module/live-activity/api.d.ts.map +1 -1
- package/build/typescript/module/live-activity/dynamic-api.d.ts +54 -0
- package/build/typescript/module/live-activity/dynamic-api.d.ts.map +1 -0
- package/build/typescript/module/native/NativeVoltra.d.ts +21 -0
- package/build/typescript/module/native/NativeVoltra.d.ts.map +1 -1
- package/build/typescript/module/types.d.ts +1 -1
- package/build/typescript/module/types.d.ts.map +1 -1
- package/build/typescript/module/utils/enableDynamicLiveActivityHotReload.d.ts +15 -0
- package/build/typescript/module/utils/enableDynamicLiveActivityHotReload.d.ts.map +1 -0
- package/build/typescript/module/utils/enableWidgetHotReload.d.ts +5 -7
- package/build/typescript/module/utils/enableWidgetHotReload.d.ts.map +1 -1
- package/build/typescript/module/utils/useUpdateOnHMR.d.ts +0 -3
- package/build/typescript/module/utils/useUpdateOnHMR.d.ts.map +1 -1
- package/build/typescript/module/widgets/server-credentials.d.ts +8 -0
- package/build/typescript/module/widgets/server-credentials.d.ts.map +1 -1
- package/build/typescript/module/widgets/server-update.d.ts +64 -0
- package/build/typescript/module/widgets/server-update.d.ts.map +1 -0
- package/expo-plugin/build/cjs/constants.js +20 -1
- package/expo-plugin/build/cjs/constants.js.map +1 -1
- package/expo-plugin/build/cjs/index.js +9 -1
- package/expo-plugin/build/cjs/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios/index.js +1 -0
- package/expo-plugin/build/cjs/ios/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios/infoPlist.js +28 -5
- package/expo-plugin/build/cjs/ios/infoPlist.js.map +1 -1
- package/expo-plugin/build/cjs/ios/serverUpdate.js +25 -0
- package/expo-plugin/build/cjs/ios/serverUpdate.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/clientRendered.js +4 -4
- package/expo-plugin/build/cjs/ios-widget/clientRendered.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/clientRenderedPrerender.js +5 -5
- package/expo-plugin/build/cjs/ios-widget/clientRenderedPrerender.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/dynamic-live-activity/swift.js +130 -0
- package/expo-plugin/build/cjs/ios-widget/dynamic-live-activity/swift.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/files/index.js +9 -2
- package/expo-plugin/build/cjs/ios-widget/files/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js +6 -3
- package/expo-plugin/build/cjs/ios-widget/files/infoPlist.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/files/manifest.js +24 -0
- package/expo-plugin/build/cjs/ios-widget/files/manifest.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/files/swift-utils.js +7 -0
- package/expo-plugin/build/cjs/ios-widget/files/swift-utils.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/files/swift.js +56 -26
- package/expo-plugin/build/cjs/ios-widget/files/swift.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/index.js +9 -3
- package/expo-plugin/build/cjs/ios-widget/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/podfile.js +38 -12
- package/expo-plugin/build/cjs/ios-widget/podfile.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/widgetPlist.js +34 -22
- package/expo-plugin/build/cjs/ios-widget/widgetPlist.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js +194 -118
- package/expo-plugin/build/cjs/ios-widget/xcode/buildPhases.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js +30 -22
- package/expo-plugin/build/cjs/ios-widget/xcode/configurationList.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js +50 -0
- package/expo-plugin/build/cjs/ios-widget/xcode/fileReferences.js.map +1 -0
- package/expo-plugin/build/cjs/ios-widget/xcode/groups.js +45 -43
- package/expo-plugin/build/cjs/ios-widget/xcode/groups.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/index.js +93 -91
- package/expo-plugin/build/cjs/ios-widget/xcode/index.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js +41 -39
- package/expo-plugin/build/cjs/ios-widget/xcode/mainAppSettings.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js +2 -2
- package/expo-plugin/build/cjs/ios-widget/xcode/productFile.js.map +1 -1
- package/expo-plugin/build/cjs/ios-widget/xcode/target.js +29 -63
- package/expo-plugin/build/cjs/ios-widget/xcode/target.js.map +1 -1
- package/expo-plugin/build/cjs/utils/urlScheme.js +36 -14
- package/expo-plugin/build/cjs/utils/urlScheme.js.map +1 -1
- package/expo-plugin/build/cjs/validation.js +54 -0
- package/expo-plugin/build/cjs/validation.js.map +1 -1
- package/expo-plugin/build/esm/constants.js +17 -0
- package/expo-plugin/build/esm/constants.js.map +1 -1
- package/expo-plugin/build/esm/index.js +9 -1
- package/expo-plugin/build/esm/index.js.map +1 -1
- package/expo-plugin/build/esm/ios/index.js +1 -0
- package/expo-plugin/build/esm/ios/index.js.map +1 -1
- package/expo-plugin/build/esm/ios/infoPlist.js +28 -5
- package/expo-plugin/build/esm/ios/infoPlist.js.map +1 -1
- package/expo-plugin/build/esm/ios/serverUpdate.js +21 -0
- package/expo-plugin/build/esm/ios/serverUpdate.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/clientRendered.js +5 -5
- package/expo-plugin/build/esm/ios-widget/clientRendered.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/clientRenderedPrerender.js +6 -6
- package/expo-plugin/build/esm/ios-widget/clientRenderedPrerender.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/dynamic-live-activity/swift.js +122 -0
- package/expo-plugin/build/esm/ios-widget/dynamic-live-activity/swift.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/files/index.js +10 -3
- package/expo-plugin/build/esm/ios-widget/files/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/files/infoPlist.js +6 -3
- package/expo-plugin/build/esm/ios-widget/files/infoPlist.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/files/manifest.js +23 -1
- package/expo-plugin/build/esm/ios-widget/files/manifest.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/files/swift-utils.js +4 -0
- package/expo-plugin/build/esm/ios-widget/files/swift-utils.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/files/swift.js +50 -20
- package/expo-plugin/build/esm/ios-widget/files/swift.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/index.js +9 -3
- package/expo-plugin/build/esm/ios-widget/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/podfile.js +36 -11
- package/expo-plugin/build/esm/ios-widget/podfile.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/widgetPlist.js +34 -22
- package/expo-plugin/build/esm/ios-widget/widgetPlist.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js +194 -117
- package/expo-plugin/build/esm/ios-widget/xcode/buildPhases.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js +31 -22
- package/expo-plugin/build/esm/ios-widget/xcode/configurationList.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js +45 -0
- package/expo-plugin/build/esm/ios-widget/xcode/fileReferences.js.map +1 -0
- package/expo-plugin/build/esm/ios-widget/xcode/groups.js +45 -42
- package/expo-plugin/build/esm/ios-widget/xcode/groups.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/index.js +97 -96
- package/expo-plugin/build/esm/ios-widget/xcode/index.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js +41 -39
- package/expo-plugin/build/esm/ios-widget/xcode/mainAppSettings.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/productFile.js +3 -2
- package/expo-plugin/build/esm/ios-widget/xcode/productFile.js.map +1 -1
- package/expo-plugin/build/esm/ios-widget/xcode/target.js +28 -62
- package/expo-plugin/build/esm/ios-widget/xcode/target.js.map +1 -1
- package/expo-plugin/build/esm/utils/urlScheme.js +34 -14
- package/expo-plugin/build/esm/utils/urlScheme.js.map +1 -1
- package/expo-plugin/build/esm/validation.js +54 -1
- package/expo-plugin/build/esm/validation.js.map +1 -1
- package/expo-plugin/build/types/constants.d.ts +10 -1
- package/expo-plugin/build/types/constants.d.ts.map +1 -1
- package/expo-plugin/build/types/index.d.ts +1 -1
- package/expo-plugin/build/types/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios/index.d.ts +2 -0
- package/expo-plugin/build/types/ios/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios/infoPlist.d.ts +2 -0
- package/expo-plugin/build/types/ios/infoPlist.d.ts.map +1 -1
- package/expo-plugin/build/types/ios/serverUpdate.d.ts +11 -0
- package/expo-plugin/build/types/ios/serverUpdate.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/clientRendered.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/clientRenderedPrerender.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/dynamic-live-activity/swift.d.ts +7 -0
- package/expo-plugin/build/types/ios-widget/dynamic-live-activity/swift.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/files/index.d.ts +3 -1
- package/expo-plugin/build/types/ios-widget/files/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts +2 -1
- package/expo-plugin/build/types/ios-widget/files/infoPlist.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/files/manifest.d.ts +9 -2
- package/expo-plugin/build/types/ios-widget/files/manifest.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/files/swift-utils.d.ts +2 -0
- package/expo-plugin/build/types/ios-widget/files/swift-utils.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/files/swift.d.ts +6 -2
- package/expo-plugin/build/types/ios-widget/files/swift.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/index.d.ts +3 -1
- package/expo-plugin/build/types/ios-widget/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/podfile.d.ts +19 -1
- package/expo-plugin/build/types/ios-widget/podfile.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/widgetPlist.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts +6 -8
- package/expo-plugin/build/types/ios-widget/xcode/buildPhases.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts +15 -10
- package/expo-plugin/build/types/ios-widget/xcode/configurationList.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts +16 -0
- package/expo-plugin/build/types/ios-widget/xcode/fileReferences.d.ts.map +1 -0
- package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts +0 -4
- package/expo-plugin/build/types/ios-widget/xcode/groups.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/index.d.ts +23 -3
- package/expo-plugin/build/types/ios-widget/xcode/index.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts +16 -4
- package/expo-plugin/build/types/ios-widget/xcode/mainAppSettings.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts +0 -4
- package/expo-plugin/build/types/ios-widget/xcode/productFile.d.ts.map +1 -1
- package/expo-plugin/build/types/ios-widget/xcode/target.d.ts +11 -26
- package/expo-plugin/build/types/ios-widget/xcode/target.d.ts.map +1 -1
- package/expo-plugin/build/types/types.d.ts +23 -4
- package/expo-plugin/build/types/types.d.ts.map +1 -1
- package/expo-plugin/build/types/utils/urlScheme.d.ts +16 -0
- package/expo-plugin/build/types/utils/urlScheme.d.ts.map +1 -1
- package/expo-plugin/build/types/validation.d.ts +2 -1
- package/expo-plugin/build/types/validation.d.ts.map +1 -1
- package/expo-plugin/src/constants.ts +24 -1
- package/expo-plugin/src/index.ts +14 -1
- package/expo-plugin/src/ios/index.ts +3 -0
- package/expo-plugin/src/ios/infoPlist.ts +33 -5
- package/expo-plugin/src/ios/serverUpdate.ts +29 -0
- package/expo-plugin/src/ios-widget/clientRendered.ts +9 -5
- package/expo-plugin/src/ios-widget/clientRenderedPrerender.ts +11 -6
- package/expo-plugin/src/ios-widget/dynamic-live-activity/swift.ts +138 -0
- package/expo-plugin/src/ios-widget/files/index.ts +15 -4
- package/expo-plugin/src/ios-widget/files/infoPlist.ts +17 -3
- package/expo-plugin/src/ios-widget/files/manifest.ts +42 -2
- package/expo-plugin/src/ios-widget/files/swift-utils.ts +3 -0
- package/expo-plugin/src/ios-widget/files/swift.ts +69 -22
- package/expo-plugin/src/ios-widget/index.ts +13 -3
- package/expo-plugin/src/ios-widget/podfile.ts +46 -13
- package/expo-plugin/src/ios-widget/widgetPlist.ts +37 -23
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/fresh.pbxproj +197 -0
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-existing-extension.pbxproj +321 -0
- package/expo-plugin/src/ios-widget/xcode/__fixtures__/with-per-config-signing.pbxproj +203 -0
- package/expo-plugin/src/ios-widget/xcode/__snapshots__/applyXcodeChanges.node.test.ts.snap +363 -0
- package/expo-plugin/src/ios-widget/xcode/__tests__/pbxConsistency.ts +130 -0
- package/expo-plugin/src/ios-widget/xcode/buildPhases.ts +210 -164
- package/expo-plugin/src/ios-widget/xcode/configurationList.ts +52 -35
- package/expo-plugin/src/ios-widget/xcode/fileReferences.ts +51 -0
- package/expo-plugin/src/ios-widget/xcode/groups.ts +52 -54
- package/expo-plugin/src/ios-widget/xcode/index.ts +124 -119
- package/expo-plugin/src/ios-widget/xcode/mainAppSettings.ts +59 -54
- package/expo-plugin/src/ios-widget/xcode/productFile.ts +3 -2
- package/expo-plugin/src/ios-widget/xcode/target.ts +31 -83
- package/expo-plugin/src/types.ts +28 -4
- package/expo-plugin/src/utils/urlScheme.ts +47 -17
- package/expo-plugin/src/validation.ts +76 -1
- package/ios/Package.swift +39 -4
- package/ios/VoltraWidget.podspec +1 -0
- package/ios/app/NativeVoltra.mm +126 -7
- package/ios/app/VoltraLiveActivityManager.swift +30 -0
- package/ios/app/VoltraLiveActivityService.swift +77 -5
- package/ios/app/VoltraModule.swift +117 -1
- package/ios/app/VoltraModuleImpl.swift +116 -2
- package/ios/app/VoltraViewComponentView.mm +3 -3
- package/ios/app/VoltraWidgetService.swift +147 -12
- package/ios/app/dynamic-live-activity/VoltraDynamicLiveActivityService.swift +97 -0
- package/ios/app/dynamic-live-activity/VoltraLiveActivityChronology.swift +68 -0
- package/ios/shared/DynamicWidgetPropsCodec.swift +51 -0
- package/ios/shared/DynamicWidgetPropsStorage.swift +53 -0
- package/ios/shared/DynamicWidgetPropsStore.swift +117 -0
- package/ios/shared/DynamicWidgetRenderCoordinator.swift +31 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerFetchResolver.swift +34 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerProps.swift +55 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerPropsStore.swift +146 -0
- package/ios/shared/DynamicWidgetServerUpdate/DynamicWidgetServerUpdateRunner.swift +193 -0
- package/ios/shared/DynamicWidgetUpdater.swift +30 -0
- package/ios/shared/ServerWidgetContentResolver.swift +60 -0
- package/ios/shared/ServerWidgetResponseStore.swift +25 -0
- package/ios/shared/ShortNames.swift +6 -0
- package/ios/shared/VoltraConfig.swift +41 -0
- package/ios/shared/VoltraConstants.swift +19 -0
- package/ios/shared/VoltraElement.swift +127 -43
- package/ios/shared/VoltraEventBus.swift +52 -7
- package/ios/shared/VoltraJSRenderer.swift +93 -23
- package/ios/shared/VoltraNode.swift +7 -111
- package/ios/shared/VoltraRefreshIntent.swift +1 -1
- package/ios/shared/VoltraWidgetDefaults.swift +9 -1
- package/ios/shared/VoltraWidgetKind.swift +41 -0
- package/ios/shared/VoltraWidgetServerFetcher.swift +52 -107
- package/ios/shared/WidgetServer/VoltraWidgetAppearance.swift +17 -0
- package/ios/shared/WidgetServer/VoltraWidgetServer.swift +138 -0
- package/ios/shared/WidgetServer/WidgetCanonicalConfiguration.swift +77 -0
- package/ios/shared/WidgetServer/WidgetScope.swift +55 -0
- package/ios/shared/WidgetServer/WidgetServerEtagStore.swift +55 -0
- package/ios/shared/WidgetServer/WidgetServerFetcher.swift +179 -0
- package/ios/shared/WidgetServer/WidgetServerRequestBuilder.swift +114 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsCodec.swift +47 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsResolver.swift +129 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsStore.swift +170 -0
- package/ios/shared/WidgetServer/WidgetServerSettingsValidator.swift +73 -0
- package/ios/shared/WidgetServer/WidgetServerUpdateSettings.swift +123 -0
- package/ios/shared/WidgetServer/WidgetServerUpdateSettingsJson.swift +115 -0
- package/ios/shared/dynamic-live-activity/DynamicLiveActivityPropsCodec.swift +13 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityBundleSource.swift +156 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityObserver.swift +97 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityOperations.swift +105 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityPayloadValidator.swift +55 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRegistry.swift +143 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureQueue.swift +158 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureReporter.swift +120 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityRenderer.swift +370 -0
- package/ios/shared/dynamic-live-activity/VoltraDynamicLiveActivityTypes.swift +87 -0
- package/ios/shared/dynamic-live-activity/VoltraLiveActivityOrder.swift +19 -0
- package/ios/target/VoltraClientWidgetRuntime.swift +60 -10
- package/ios/target/VoltraDynamicWidgetServerUpdateProvider.swift +204 -0
- package/ios/target/VoltraHomeWidget.swift +91 -92
- package/ios/target/VoltraWidget.swift +3 -1
- package/ios/ui/Extensions/VoltraNode+View.swift +113 -0
- package/ios/ui/Generated/Parameters/ChartParameters.swift +3 -0
- package/ios/ui/Helpers/VoltraDeepLinkResolver.swift +5 -3
- package/ios/ui/Helpers/VoltraProgressDriver.swift +6 -2
- package/ios/ui/Layout/VoltraFlexStackLayout.swift +9 -3
- package/ios/ui/Style/JSColorParser.swift +24 -8
- package/ios/ui/Style/JSGradientParser.swift +36 -12
- package/ios/ui/Style/JSStyleParser.swift +36 -12
- package/ios/ui/Style/LayoutStyle.swift +12 -4
- package/ios/ui/Views/VoltraChart.swift +160 -16
- package/ios/ui/Views/VoltraLinearGradient.swift +6 -2
- package/package.json +5 -5
- package/src/dynamic-widget/api.ts +25 -0
- package/src/events.ts +34 -0
- package/src/index.ts +23 -0
- package/src/live-activity/api.ts +2 -2
- package/src/live-activity/dynamic-api.ts +240 -0
- package/src/native/NativeVoltra.ts +22 -0
- package/src/types.ts +4 -0
- package/src/utils/enableDynamicLiveActivityHotReload.ts +50 -0
- package/src/utils/enableWidgetHotReload.ts +9 -16
- package/src/utils/useUpdateOnHMR.ts +3 -12
- package/src/widgets/server-credentials.ts +8 -0
- package/src/widgets/server-update.ts +84 -0
- /package/ios/shared/{VoltraKeychainHelper.swift → WidgetServer/VoltraKeychainHelper.swift} +0 -0
|
@@ -1,27 +1,55 @@
|
|
|
1
1
|
import { XcodeProject } from '@expo/config-plugins'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
/** Code-signing settings read from one of the main app target's build configurations. */
|
|
4
|
+
export interface MainAppSigningSettings {
|
|
5
5
|
codeSignStyle?: string
|
|
6
6
|
developmentTeam?: string
|
|
7
7
|
provisioningProfileSpecifier?: string
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
export interface MainAppTargetSettings {
|
|
11
|
+
/**
|
|
12
|
+
* Signing settings keyed by build-configuration name (e.g. `Debug`, `Release`). Release
|
|
13
|
+
* provisioning often differs from Debug, so the widget must mirror the main app per
|
|
14
|
+
* configuration rather than copying one configuration's signing into both.
|
|
15
|
+
*/
|
|
16
|
+
byConfigurationName: Record<string, MainAppSigningSettings>
|
|
17
|
+
/** The first configuration's settings, used for widget configurations with no name match. */
|
|
18
|
+
fallback: MainAppSigningSettings
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** Strips surrounding quotes from a raw build-setting value. */
|
|
22
|
+
function unquote(value: unknown): string | undefined {
|
|
23
|
+
if (typeof value !== 'string') {
|
|
24
|
+
return undefined
|
|
25
|
+
}
|
|
26
|
+
return value.replace(/^"|"$/g, '')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** Reads the signing-related build settings from a single XCBuildConfiguration. */
|
|
30
|
+
function readSigningSettings(buildSettings: Record<string, unknown>): MainAppSigningSettings {
|
|
31
|
+
return {
|
|
32
|
+
codeSignStyle: unquote(buildSettings.CODE_SIGN_STYLE),
|
|
33
|
+
developmentTeam: unquote(buildSettings.DEVELOPMENT_TEAM),
|
|
34
|
+
provisioningProfileSpecifier: unquote(buildSettings.PROVISIONING_PROFILE_SPECIFIER),
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
10
38
|
/**
|
|
11
|
-
* Reads build settings from the main app target
|
|
39
|
+
* Reads code-signing build settings from every build configuration of the main app target, so the
|
|
40
|
+
* widget extension can synchronize signing per configuration (Debug→Debug, Release→Release).
|
|
12
41
|
*
|
|
13
42
|
* @param xcodeProject The Xcode project instance
|
|
14
|
-
* @returns
|
|
43
|
+
* @returns Signing settings keyed by configuration name plus a first-configuration fallback, or
|
|
44
|
+
* null when the main app target or its configurations cannot be resolved
|
|
15
45
|
*/
|
|
16
46
|
export function getMainAppTargetSettings(xcodeProject: XcodeProject): MainAppTargetSettings | null {
|
|
17
47
|
try {
|
|
18
48
|
const mainAppTarget = xcodeProject.getFirstTarget()?.firstTarget
|
|
19
|
-
|
|
20
49
|
if (!mainAppTarget) {
|
|
21
50
|
return null
|
|
22
51
|
}
|
|
23
52
|
|
|
24
|
-
// Get the build configuration list for the main app target
|
|
25
53
|
const buildConfigurationListId = mainAppTarget.buildConfigurationList
|
|
26
54
|
if (!buildConfigurationListId) {
|
|
27
55
|
return null
|
|
@@ -32,62 +60,39 @@ export function getMainAppTargetSettings(xcodeProject: XcodeProject): MainAppTar
|
|
|
32
60
|
|
|
33
61
|
const buildConfigurationList =
|
|
34
62
|
xcodeProject.hash.project.objects['XCConfigurationList']?.[buildConfigurationListUuid]
|
|
35
|
-
if (!buildConfigurationList
|
|
36
|
-
return null
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Get the first build configuration (usually Debug) to read settings
|
|
40
|
-
const firstConfigRef = buildConfigurationList.buildConfigurations[0]
|
|
41
|
-
if (!firstConfigRef) {
|
|
42
|
-
return null
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Extract UUID from config reference (it might include a comment)
|
|
46
|
-
const firstConfigUuid =
|
|
47
|
-
typeof firstConfigRef === 'string' ? firstConfigRef.split(' ')[0] : firstConfigRef.value?.split(' ')[0]
|
|
48
|
-
if (!firstConfigUuid) {
|
|
63
|
+
if (!buildConfigurationList?.buildConfigurations) {
|
|
49
64
|
return null
|
|
50
65
|
}
|
|
51
66
|
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
67
|
+
const buildConfigurationSection = xcodeProject.hash.project.objects['XCBuildConfiguration'] ?? {}
|
|
68
|
+
const byConfigurationName: Record<string, MainAppSigningSettings> = {}
|
|
69
|
+
let fallback: MainAppSigningSettings | null = null
|
|
70
|
+
|
|
71
|
+
for (const configRef of buildConfigurationList.buildConfigurations) {
|
|
72
|
+
// Extract UUID from the config reference (it might include a comment)
|
|
73
|
+
const configUuid = typeof configRef === 'string' ? configRef.split(' ')[0] : configRef.value?.split(' ')[0]
|
|
74
|
+
if (!configUuid) {
|
|
75
|
+
continue
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const buildConfiguration = buildConfigurationSection[configUuid]
|
|
79
|
+
if (!buildConfiguration?.buildSettings) {
|
|
80
|
+
continue
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const settings = readSigningSettings(buildConfiguration.buildSettings)
|
|
84
|
+
const configName = unquote(buildConfiguration.name)
|
|
85
|
+
if (configName && !(configName in byConfigurationName)) {
|
|
86
|
+
byConfigurationName[configName] = settings
|
|
87
|
+
}
|
|
88
|
+
fallback = fallback ?? settings
|
|
55
89
|
}
|
|
56
90
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// Extract deployment target (remove quotes if present)
|
|
60
|
-
const deploymentTarget =
|
|
61
|
-
buildSettings.IPHONEOS_DEPLOYMENT_TARGET?.replace(/^"|"$/g, '') ||
|
|
62
|
-
buildSettings['IPHONEOS_DEPLOYMENT_TARGET']?.replace(/^"|"$/g, '') ||
|
|
63
|
-
null
|
|
64
|
-
|
|
65
|
-
// Extract code signing settings
|
|
66
|
-
const codeSignStyle =
|
|
67
|
-
buildSettings.CODE_SIGN_STYLE?.replace(/^"|"$/g, '') ||
|
|
68
|
-
buildSettings['CODE_SIGN_STYLE']?.replace(/^"|"$/g, '') ||
|
|
69
|
-
null
|
|
70
|
-
|
|
71
|
-
const developmentTeam =
|
|
72
|
-
buildSettings.DEVELOPMENT_TEAM?.replace(/^"|"$/g, '') ||
|
|
73
|
-
buildSettings['DEVELOPMENT_TEAM']?.replace(/^"|"$/g, '') ||
|
|
74
|
-
null
|
|
75
|
-
|
|
76
|
-
const provisioningProfileSpecifier =
|
|
77
|
-
buildSettings.PROVISIONING_PROFILE_SPECIFIER?.replace(/^"|"$/g, '') ||
|
|
78
|
-
buildSettings['PROVISIONING_PROFILE_SPECIFIER']?.replace(/^"|"$/g, '') ||
|
|
79
|
-
null
|
|
80
|
-
|
|
81
|
-
if (!deploymentTarget) {
|
|
91
|
+
if (!fallback) {
|
|
82
92
|
return null
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
return {
|
|
86
|
-
deploymentTarget,
|
|
87
|
-
codeSignStyle: codeSignStyle || undefined,
|
|
88
|
-
developmentTeam: developmentTeam || undefined,
|
|
89
|
-
provisioningProfileSpecifier: provisioningProfileSpecifier || undefined,
|
|
90
|
-
}
|
|
95
|
+
return { byConfigurationName, fallback }
|
|
91
96
|
} catch {
|
|
92
97
|
// If we can't read the settings, return null and use fallback values
|
|
93
98
|
return null
|
|
@@ -42,9 +42,10 @@ function findBuildFileForFileRef(xcodeProject: XcodeProject, fileRef: string): {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
|
-
* Adds the product file (.appex) for the widget extension.
|
|
45
|
+
* Adds the product file (.appex) for the widget extension. Internal create-only fallback for
|
|
46
|
+
* {@link ensureProductFile}; not part of the public pipeline.
|
|
46
47
|
*/
|
|
47
|
-
|
|
48
|
+
function addProductFile(xcodeProject: XcodeProject, options: AddProductFileOptions) {
|
|
48
49
|
const { targetName, groupName } = options
|
|
49
50
|
|
|
50
51
|
const productFileOptions = {
|
|
@@ -6,18 +6,9 @@ import { IOS } from '../../constants'
|
|
|
6
6
|
// Types
|
|
7
7
|
// ============================================================================
|
|
8
8
|
|
|
9
|
-
export interface
|
|
9
|
+
export interface CreateTargetSkeletonOptions {
|
|
10
10
|
targetName: string
|
|
11
11
|
targetUuid: string
|
|
12
|
-
productFile: { fileRef: string }
|
|
13
|
-
xCConfigurationList: { uuid: string }
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
interface AddNativeTargetOptions {
|
|
17
|
-
targetName: string
|
|
18
|
-
targetUuid: string
|
|
19
|
-
productFile: { fileRef: string }
|
|
20
|
-
xCConfigurationList: { uuid: string }
|
|
21
12
|
}
|
|
22
13
|
|
|
23
14
|
// ============================================================================
|
|
@@ -25,19 +16,39 @@ interface AddNativeTargetOptions {
|
|
|
25
16
|
// ============================================================================
|
|
26
17
|
|
|
27
18
|
/**
|
|
28
|
-
*
|
|
19
|
+
* Creates the minimal widget-extension native target and registers it with the project.
|
|
20
|
+
*
|
|
21
|
+
* A target cannot be "ensured" into existence, so this is the one create-only step in
|
|
22
|
+
* {@link applyXcodeChanges}: it adds an empty `PBXNativeTarget` (no product reference, configuration
|
|
23
|
+
* list or build phases yet) to the `PBXNativeTarget` and `PBXProject` sections. The shared ensure
|
|
24
|
+
* pipeline then fills in the configuration list, product file, group, build phases, attributes and
|
|
25
|
+
* dependency — the same code that reconciles an already-existing target.
|
|
29
26
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
* - Adds the target to PBXProject section
|
|
33
|
-
* - Adds a dependency from the main app to the widget extension
|
|
27
|
+
* @returns The freshly created native-target object (the value stored in the `PBXNativeTarget`
|
|
28
|
+
* section under `targetUuid`).
|
|
34
29
|
*/
|
|
35
|
-
export function
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
export function createTargetSkeleton(xcodeProject: XcodeProject, options: CreateTargetSkeletonOptions) {
|
|
31
|
+
const { targetName, targetUuid } = options
|
|
32
|
+
|
|
33
|
+
const target = {
|
|
34
|
+
uuid: targetUuid,
|
|
35
|
+
pbxNativeTarget: {
|
|
36
|
+
isa: 'PBXNativeTarget',
|
|
37
|
+
name: targetName,
|
|
38
|
+
productName: targetName,
|
|
39
|
+
productType: `"com.apple.product-type.app-extension"`,
|
|
40
|
+
buildConfigurationList: '',
|
|
41
|
+
productReference: '',
|
|
42
|
+
buildPhases: [],
|
|
43
|
+
buildRules: [],
|
|
44
|
+
dependencies: [],
|
|
45
|
+
},
|
|
46
|
+
}
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
xcodeProject.addToPbxNativeTargetSection(target)
|
|
49
|
+
xcodeProject.addToPbxProjectSection(target)
|
|
50
|
+
|
|
51
|
+
return xcodeProject.pbxNativeTargetSection()[targetUuid]
|
|
41
52
|
}
|
|
42
53
|
|
|
43
54
|
/**
|
|
@@ -83,66 +94,3 @@ export function ensureTargetDependency(xcodeProject: XcodeProject, targetUuid: s
|
|
|
83
94
|
xcodeProject.addTargetDependency(mainTargetUuid, [targetUuid])
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
|
-
|
|
87
|
-
// ============================================================================
|
|
88
|
-
// Helper Functions
|
|
89
|
-
// ============================================================================
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Adds the widget extension target to the PBXNativeTarget section.
|
|
93
|
-
*/
|
|
94
|
-
function addToPbxNativeTargetSection(xcodeProject: XcodeProject, options: AddNativeTargetOptions) {
|
|
95
|
-
const { targetName, targetUuid, productFile, xCConfigurationList } = options
|
|
96
|
-
|
|
97
|
-
const target = {
|
|
98
|
-
uuid: targetUuid,
|
|
99
|
-
pbxNativeTarget: {
|
|
100
|
-
isa: 'PBXNativeTarget',
|
|
101
|
-
name: targetName,
|
|
102
|
-
productName: targetName,
|
|
103
|
-
productReference: productFile.fileRef,
|
|
104
|
-
productType: `"com.apple.product-type.app-extension"`,
|
|
105
|
-
buildConfigurationList: xCConfigurationList.uuid,
|
|
106
|
-
buildPhases: [],
|
|
107
|
-
buildRules: [],
|
|
108
|
-
dependencies: [],
|
|
109
|
-
},
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
xcodeProject.addToPbxNativeTargetSection(target)
|
|
113
|
-
|
|
114
|
-
return target
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Adds the target to the PBXProject section.
|
|
119
|
-
*/
|
|
120
|
-
function addToPbxProjectSection(xcodeProject: XcodeProject, target: { uuid: string }): void {
|
|
121
|
-
xcodeProject.addToPbxProjectSection(target)
|
|
122
|
-
|
|
123
|
-
// Add target attributes to project section
|
|
124
|
-
const projectSection = xcodeProject.pbxProjectSection()
|
|
125
|
-
const firstProject = xcodeProject.getFirstProject()
|
|
126
|
-
|
|
127
|
-
if (!projectSection[firstProject.uuid].attributes.TargetAttributes) {
|
|
128
|
-
projectSection[firstProject.uuid].attributes.TargetAttributes = {}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
projectSection[firstProject.uuid].attributes.TargetAttributes[target.uuid] = {
|
|
132
|
-
LastSwiftMigration: IOS.LAST_SWIFT_MIGRATION,
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* Adds a target dependency so the main app depends on the widget extension.
|
|
138
|
-
*/
|
|
139
|
-
function addTargetDependency(xcodeProject: XcodeProject, target: { uuid: string }): void {
|
|
140
|
-
if (!xcodeProject.hash.project.objects['PBXTargetDependency']) {
|
|
141
|
-
xcodeProject.hash.project.objects['PBXTargetDependency'] = {}
|
|
142
|
-
}
|
|
143
|
-
if (!xcodeProject.hash.project.objects['PBXContainerItemProxy']) {
|
|
144
|
-
xcodeProject.hash.project.objects['PBXContainerItemProxy'] = {}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
xcodeProject.addTargetDependency(xcodeProject.getFirstTarget().uuid, [target.uuid])
|
|
148
|
-
}
|
package/expo-plugin/src/types.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import type { ConfigPlugin } from '@expo/config-plugins'
|
|
2
2
|
|
|
3
|
-
import type {
|
|
3
|
+
import type {
|
|
4
|
+
DynamicLiveActivityEntryConfig,
|
|
5
|
+
DynamicWidgetEntryConfig,
|
|
6
|
+
WidgetInitialStatePath,
|
|
7
|
+
WidgetLabel,
|
|
8
|
+
} from '@use-voltra/expo-plugin'
|
|
4
9
|
|
|
5
10
|
/**
|
|
6
11
|
* Supported iOS Home Screen widget size families.
|
|
@@ -42,9 +47,15 @@ export interface IOSWidgetAppIntentConfig {
|
|
|
42
47
|
*/
|
|
43
48
|
export interface IOSWidgetConfig extends DynamicWidgetEntryConfig {
|
|
44
49
|
/**
|
|
45
|
-
* Unique identifier for the widget (used
|
|
50
|
+
* Unique identifier for the widget (used in the JS API and, unless `kind` is set, as the widget kind)
|
|
46
51
|
*/
|
|
47
52
|
id: string
|
|
53
|
+
/**
|
|
54
|
+
* WidgetKit `kind` of the generated widget. Defaults to `Voltra_Widget_<id>`.
|
|
55
|
+
* Pin it to the kind of a pre-Voltra widget so already placed instances survive the migration
|
|
56
|
+
* (WidgetKit identifies a placed widget by extension bundle id + kind).
|
|
57
|
+
*/
|
|
58
|
+
kind?: string
|
|
48
59
|
displayName: WidgetLabel
|
|
49
60
|
description: WidgetLabel
|
|
50
61
|
/** @default ['systemSmall', 'systemMedium', 'systemLarge'] */
|
|
@@ -60,12 +71,22 @@ export interface IOSWidgetConfig extends DynamicWidgetEntryConfig {
|
|
|
60
71
|
appIntent?: IOSWidgetAppIntentConfig
|
|
61
72
|
}
|
|
62
73
|
|
|
74
|
+
/**
|
|
75
|
+
* A Dynamic Live Activity bundled with the app.
|
|
76
|
+
* @experimental
|
|
77
|
+
*/
|
|
78
|
+
export interface IOSDynamicLiveActivityConfig extends DynamicLiveActivityEntryConfig {}
|
|
79
|
+
|
|
63
80
|
/**
|
|
64
81
|
* Server-driven iOS widget updates (WidgetKit background refresh).
|
|
65
82
|
*/
|
|
66
83
|
export interface IOSWidgetServerUpdateConfig {
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
/**
|
|
85
|
+
* Server endpoint that returns widget state updates. Omit it to mark the widget
|
|
86
|
+
* server-driven and supply the URL at runtime with `setWidgetServerUpdate`.
|
|
87
|
+
*/
|
|
88
|
+
url?: string
|
|
89
|
+
/** @default 15, or 15 when the widget has an `entry` */
|
|
69
90
|
intervalMinutes?: number
|
|
70
91
|
/** @default false */
|
|
71
92
|
refresh?: boolean
|
|
@@ -91,6 +112,8 @@ export interface IOSConfigPluginProps {
|
|
|
91
112
|
enablePushNotifications?: boolean
|
|
92
113
|
groupIdentifier?: string
|
|
93
114
|
widgets?: IOSWidgetConfig[]
|
|
115
|
+
/** @experimental Dynamic Live Activities rendered from bundled JavaScript entries. */
|
|
116
|
+
liveActivities?: IOSDynamicLiveActivityConfig[]
|
|
94
117
|
deploymentTarget?: string
|
|
95
118
|
targetName?: string
|
|
96
119
|
fonts?: string[]
|
|
@@ -111,6 +134,7 @@ export interface IOSWidgetExtensionPluginProps {
|
|
|
111
134
|
bundleIdentifier: string
|
|
112
135
|
deploymentTarget: string
|
|
113
136
|
widgets?: IOSWidgetConfig[]
|
|
137
|
+
liveActivities?: IOSDynamicLiveActivityConfig[]
|
|
114
138
|
groupIdentifier?: string
|
|
115
139
|
keychainGroup?: string
|
|
116
140
|
fonts?: string[]
|
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
import type { ExpoConfig } from 'expo/config'
|
|
2
2
|
|
|
3
|
+
type URLType = { CFBundleURLSchemes?: unknown }
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The URL schemes the app is configured with: every `scheme` and `ios.scheme` value (string or
|
|
7
|
+
* array), or the bundle identifier when neither is set.
|
|
8
|
+
*/
|
|
9
|
+
export function getAppURLSchemes(config: ExpoConfig): string[] {
|
|
10
|
+
const configured = [config.scheme, (config.ios as { scheme?: string | string[] } | undefined)?.scheme]
|
|
11
|
+
.flat()
|
|
12
|
+
.filter((scheme): scheme is string => typeof scheme === 'string' && scheme.length > 0)
|
|
13
|
+
|
|
14
|
+
if (configured.length > 0) {
|
|
15
|
+
return [...new Set(configured)]
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return config.ios?.bundleIdentifier ? [config.ios.bundleIdentifier] : []
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Appends a URL type for every scheme not already listed. Returns `types` itself when nothing is
|
|
23
|
+
* missing.
|
|
24
|
+
*/
|
|
25
|
+
export function appendMissingURLSchemes<T extends URLType>(
|
|
26
|
+
types: T[],
|
|
27
|
+
schemes: string[]
|
|
28
|
+
): (T | { CFBundleURLSchemes: string[] })[] {
|
|
29
|
+
const missingSchemes = schemes.filter(
|
|
30
|
+
(scheme) => !types.some((t) => Array.isArray(t?.CFBundleURLSchemes) && t.CFBundleURLSchemes.includes(scheme))
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
if (missingSchemes.length === 0) {
|
|
34
|
+
return types
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return [...types, ...missingSchemes.map((scheme) => ({ CFBundleURLSchemes: [scheme] }))]
|
|
38
|
+
}
|
|
39
|
+
|
|
3
40
|
/**
|
|
4
41
|
* Ensures the main app has a URL scheme set so widgetURL can open it.
|
|
5
42
|
* This is an optional feature for deep linking from widgets.
|
|
@@ -8,37 +45,30 @@ import type { ExpoConfig } from 'expo/config'
|
|
|
8
45
|
* @returns The modified config with URL scheme ensured
|
|
9
46
|
*/
|
|
10
47
|
export function ensureURLScheme(config: ExpoConfig): ExpoConfig {
|
|
11
|
-
const
|
|
48
|
+
const existingInfoPlist = config.ios?.infoPlist
|
|
49
|
+
const existingTypes = existingInfoPlist?.CFBundleURLTypes as URLType[] | undefined
|
|
12
50
|
|
|
13
|
-
|
|
51
|
+
// Expo's own withScheme fills CFBundleURLTypes from `scheme` / `ios.scheme` and always appends
|
|
52
|
+
// ios.bundleIdentifier, but it skips the app entirely once ios.infoPlist.CFBundleURLTypes is set
|
|
53
|
+
// (createInfoPlistPluginWithPropertyGuard). Writing the key here when the app hasn't set it
|
|
54
|
+
// therefore drops every configured scheme instead of adding one. Only top up a list the app owns.
|
|
55
|
+
if (!existingTypes) {
|
|
14
56
|
return config
|
|
15
57
|
}
|
|
16
58
|
|
|
17
|
-
const
|
|
18
|
-
const existingTypes = (existingInfoPlist.CFBundleURLTypes as any[]) || []
|
|
19
|
-
|
|
20
|
-
// Check if scheme already exists
|
|
21
|
-
const hasScheme = existingTypes.some(
|
|
22
|
-
(t) => Array.isArray(t?.CFBundleURLSchemes) && t.CFBundleURLSchemes.includes(scheme)
|
|
23
|
-
)
|
|
59
|
+
const types = appendMissingURLSchemes(existingTypes, getAppURLSchemes(config))
|
|
24
60
|
|
|
25
|
-
if (
|
|
61
|
+
if (types === existingTypes) {
|
|
26
62
|
return config
|
|
27
63
|
}
|
|
28
64
|
|
|
29
|
-
// Add the URL scheme
|
|
30
65
|
return {
|
|
31
66
|
...config,
|
|
32
67
|
ios: {
|
|
33
68
|
...config.ios,
|
|
34
69
|
infoPlist: {
|
|
35
70
|
...existingInfoPlist,
|
|
36
|
-
CFBundleURLTypes:
|
|
37
|
-
...existingTypes,
|
|
38
|
-
{
|
|
39
|
-
CFBundleURLSchemes: [scheme],
|
|
40
|
-
},
|
|
41
|
-
],
|
|
71
|
+
CFBundleURLTypes: types,
|
|
42
72
|
},
|
|
43
73
|
},
|
|
44
74
|
}
|
|
@@ -3,9 +3,14 @@ import {
|
|
|
3
3
|
validateInitialStatePath,
|
|
4
4
|
validateWidgetEntry,
|
|
5
5
|
validateWidgetLabel,
|
|
6
|
+
validateWidgetServerUpdate,
|
|
6
7
|
} from '@use-voltra/expo-plugin'
|
|
7
8
|
|
|
8
|
-
import
|
|
9
|
+
import { iosServerUpdateRules } from './ios/serverUpdate'
|
|
10
|
+
import { getDynamicLiveActivityAttributesType } from '@use-voltra/expo-plugin'
|
|
11
|
+
|
|
12
|
+
import { widgetKind } from './constants'
|
|
13
|
+
import type { IOSConfigPluginProps, IOSDynamicLiveActivityConfig, IOSWidgetConfig, IOSWidgetFamily } from './types'
|
|
9
14
|
|
|
10
15
|
const VALID_FAMILIES: Set<IOSWidgetFamily> = new Set([
|
|
11
16
|
'systemSmall',
|
|
@@ -16,9 +21,31 @@ const VALID_FAMILIES: Set<IOSWidgetFamily> = new Set([
|
|
|
16
21
|
'accessoryRectangular',
|
|
17
22
|
'accessoryInline',
|
|
18
23
|
])
|
|
24
|
+
const DYNAMIC_LIVE_ACTIVITY_ID_PATTERN = /^[a-zA-Z0-9_]+$/
|
|
25
|
+
|
|
26
|
+
export function validateIOSDynamicLiveActivityConfig(
|
|
27
|
+
liveActivity: IOSDynamicLiveActivityConfig,
|
|
28
|
+
projectRoot?: string
|
|
29
|
+
): void {
|
|
30
|
+
if (!liveActivity.id || typeof liveActivity.id !== 'string') {
|
|
31
|
+
throw new Error('Dynamic Live Activity ID is required and must be a string')
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!DYNAMIC_LIVE_ACTIVITY_ID_PATTERN.test(liveActivity.id)) {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`Dynamic Live Activity ID '${liveActivity.id}' is invalid. ` +
|
|
37
|
+
'It must be non-empty and contain only alphanumeric characters and underscores.'
|
|
38
|
+
)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
validateWidgetEntry(liveActivity.entry, liveActivity.id, projectRoot)
|
|
42
|
+
}
|
|
19
43
|
|
|
20
44
|
export function validateIOSWidgetConfig(widget: IOSWidgetConfig, projectRoot?: string): void {
|
|
21
45
|
validateHomeScreenWidgetId(widget.id)
|
|
46
|
+
if (widget.kind !== undefined && (typeof widget.kind !== 'string' || widget.kind.trim() === '')) {
|
|
47
|
+
throw new Error(`Widget '${widget.id}': kind must be a non-empty string`)
|
|
48
|
+
}
|
|
22
49
|
validateWidgetLabel(widget.displayName, widget.id, 'displayName')
|
|
23
50
|
validateWidgetLabel(widget.description, widget.id, 'description')
|
|
24
51
|
validateInitialStatePath(widget.initialStatePath, widget.id, projectRoot)
|
|
@@ -27,6 +54,8 @@ export function validateIOSWidgetConfig(widget: IOSWidgetConfig, projectRoot?: s
|
|
|
27
54
|
validateWidgetEntry(widget.entry, widget.id, projectRoot)
|
|
28
55
|
}
|
|
29
56
|
|
|
57
|
+
validateWidgetServerUpdate(widget.serverUpdate, widget.id, iosServerUpdateRules(widget))
|
|
58
|
+
|
|
30
59
|
if (widget.supportedFamilies) {
|
|
31
60
|
if (!Array.isArray(widget.supportedFamilies)) {
|
|
32
61
|
throw new Error(`Widget '${widget.id}': supportedFamilies must be an array`)
|
|
@@ -60,13 +89,59 @@ export function validateIOSConfigPluginProps(props: IOSConfigPluginProps, projec
|
|
|
60
89
|
}
|
|
61
90
|
|
|
62
91
|
const seenIds = new Set<string>()
|
|
92
|
+
const seenKinds = new Set<string>()
|
|
63
93
|
for (const widget of props.widgets) {
|
|
64
94
|
validateIOSWidgetConfig(widget, projectRoot)
|
|
65
95
|
|
|
96
|
+
// A server-driven Dynamic Widget commits fetched props to the App Group so the widget
|
|
97
|
+
// extension can read them. Without one it would fetch and have nowhere to put the result.
|
|
98
|
+
if (widget.entry !== undefined && widget.serverUpdate !== undefined && !props.groupIdentifier) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
`Widget '${widget.id}' has both entry and serverUpdate, which requires groupIdentifier ` +
|
|
101
|
+
'so fetched props can be shared with the widget extension.'
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
66
105
|
if (seenIds.has(widget.id)) {
|
|
67
106
|
throw new Error(`Duplicate widget ID: '${widget.id}'`)
|
|
68
107
|
}
|
|
69
108
|
seenIds.add(widget.id)
|
|
109
|
+
|
|
110
|
+
const kind = widgetKind(widget)
|
|
111
|
+
if (seenKinds.has(kind)) {
|
|
112
|
+
throw new Error(`Duplicate widget kind: '${kind}'`)
|
|
113
|
+
}
|
|
114
|
+
seenKinds.add(kind)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (props.liveActivities !== undefined) {
|
|
119
|
+
if (!Array.isArray(props.liveActivities)) {
|
|
120
|
+
throw new Error('liveActivities must be an array')
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (props.liveActivities.length > 0 && !props.groupIdentifier) {
|
|
124
|
+
throw new Error('groupIdentifier is required when liveActivities is non-empty')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const seenIds = new Set<string>()
|
|
128
|
+
const seenAttributesTypes = new Map<string, string>()
|
|
129
|
+
for (const liveActivity of props.liveActivities) {
|
|
130
|
+
validateIOSDynamicLiveActivityConfig(liveActivity, projectRoot)
|
|
131
|
+
|
|
132
|
+
if (seenIds.has(liveActivity.id)) {
|
|
133
|
+
throw new Error(`Duplicate Dynamic Live Activity ID: '${liveActivity.id}'`)
|
|
134
|
+
}
|
|
135
|
+
seenIds.add(liveActivity.id)
|
|
136
|
+
|
|
137
|
+
const attributesType = getDynamicLiveActivityAttributesType(liveActivity.id)
|
|
138
|
+
const conflictingId = seenAttributesTypes.get(attributesType)
|
|
139
|
+
if (conflictingId) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Dynamic Live Activity IDs '${conflictingId}' and '${liveActivity.id}' generate the same ActivityKit attributes type '${attributesType}'`
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
seenAttributesTypes.set(attributesType, liveActivity.id)
|
|
70
145
|
}
|
|
71
146
|
}
|
|
72
147
|
}
|
package/ios/Package.swift
CHANGED
|
@@ -25,23 +25,58 @@ let package = Package(
|
|
|
25
25
|
"BrotliCompression.swift",
|
|
26
26
|
"Data+hexString.swift",
|
|
27
27
|
"Date+toTimerInterval.swift",
|
|
28
|
-
"ShortNames.swift",
|
|
29
28
|
"VoltraAttributes.swift",
|
|
30
|
-
"VoltraConfig.swift",
|
|
31
|
-
"VoltraElement.swift",
|
|
32
29
|
"VoltraEvent.swift",
|
|
33
30
|
"VoltraEventBus.swift",
|
|
34
31
|
"VoltraImageStore.swift",
|
|
35
32
|
"VoltraInteractionIntent.swift",
|
|
36
33
|
"VoltraLiveActivityPayload.swift",
|
|
37
|
-
"VoltraNode.swift",
|
|
38
34
|
"VoltraPersistentEventQueue.swift",
|
|
39
35
|
],
|
|
40
36
|
sources: [
|
|
37
|
+
"DynamicWidgetPropsCodec.swift",
|
|
38
|
+
"DynamicWidgetPropsStorage.swift",
|
|
39
|
+
"DynamicWidgetPropsStore.swift",
|
|
40
|
+
"DynamicWidgetRenderCoordinator.swift",
|
|
41
|
+
"DynamicWidgetUpdater.swift",
|
|
42
|
+
"ServerWidgetContentResolver.swift",
|
|
43
|
+
"ServerWidgetResponseStore.swift",
|
|
44
|
+
// The settings stack's pure half. The Keychain-, Bundle- and URLSession-backed files in
|
|
45
|
+
// this folder are compiled only by the podspec, which ships the whole tree.
|
|
46
|
+
"WidgetServer/WidgetScope.swift",
|
|
47
|
+
"WidgetServer/WidgetCanonicalConfiguration.swift",
|
|
48
|
+
"WidgetServer/WidgetServerUpdateSettings.swift",
|
|
49
|
+
"WidgetServer/WidgetServerSettingsResolver.swift",
|
|
50
|
+
"WidgetServer/WidgetServerSettingsCodec.swift",
|
|
51
|
+
"WidgetServer/WidgetServerSettingsValidator.swift",
|
|
52
|
+
"WidgetServer/WidgetServerRequestBuilder.swift",
|
|
53
|
+
"WidgetServer/WidgetServerFetcher.swift",
|
|
54
|
+
"WidgetServer/WidgetServerSettingsStore.swift",
|
|
55
|
+
"WidgetServer/WidgetServerEtagStore.swift",
|
|
56
|
+
"WidgetServer/VoltraKeychainHelper.swift",
|
|
57
|
+
"WidgetServer/VoltraWidgetServer.swift",
|
|
58
|
+
"WidgetServer/WidgetServerUpdateSettingsJson.swift",
|
|
59
|
+
"DynamicWidgetServerUpdate/DynamicWidgetServerProps.swift",
|
|
60
|
+
"DynamicWidgetServerUpdate/DynamicWidgetServerPropsStore.swift",
|
|
61
|
+
"DynamicWidgetServerUpdate/DynamicWidgetServerFetchResolver.swift",
|
|
62
|
+
"DynamicWidgetServerUpdate/DynamicWidgetServerUpdateRunner.swift",
|
|
63
|
+
"VoltraLogger.swift",
|
|
64
|
+
"dynamic-live-activity/VoltraDynamicLiveActivityTypes.swift",
|
|
65
|
+
"dynamic-live-activity/VoltraDynamicLiveActivityPayloadValidator.swift",
|
|
66
|
+
"dynamic-live-activity/VoltraDynamicLiveActivityRenderFailureQueue.swift",
|
|
67
|
+
"dynamic-live-activity/VoltraLiveActivityOrder.swift",
|
|
41
68
|
"JSONValue.swift",
|
|
69
|
+
"VoltraConfig.swift",
|
|
70
|
+
"VoltraConstants.swift",
|
|
71
|
+
"VoltraWidgetKind.swift",
|
|
42
72
|
"VoltraPayloadMigrator.swift",
|
|
43
73
|
"VoltraRegion.swift",
|
|
44
74
|
"ComponentTypeID.swift",
|
|
75
|
+
// The JSON -> AST types. They carry no SwiftUI dependency; rendering is attached
|
|
76
|
+
// by `ui/VoltraNode+View.swift`, which the podspecs compile alongside them.
|
|
77
|
+
"ShortNames.swift",
|
|
78
|
+
"VoltraElement.swift",
|
|
79
|
+
"VoltraNode.swift",
|
|
45
80
|
]
|
|
46
81
|
),
|
|
47
82
|
.testTarget(
|