@appsonair.ir/react-native 1.0.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/android/build/.transforms/200c703f56cba8293fae35d5b35891b9/results.bin +1 -0
- package/android/build/.transforms/200c703f56cba8293fae35d5b35891b9/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/results.bin +1 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/BuildConfig.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAApkInstallHelper.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAReactHostFactory.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTARestartActivity.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTARestartHelper.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAUpdaterModule$1.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAUpdaterModule$Companion.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAUpdaterModule.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAUpdaterPackage.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAUpdaterStorage$NativeInfo.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAUpdaterStorage.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/otaupdater/OTAZipExtractHelper.dex +0 -0
- package/android/build/.transforms/258459e9c210bd80984731dbf1be5d94/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/generated/source/buildConfig/debug/com/otaupdater/BuildConfig.java +10 -0
- package/android/build/generated/source/codegen/jni/CMakeLists.txt +28 -0
- package/android/build/generated/source/codegen/jni/OtaUpdaterSpec-generated.cpp +22 -0
- package/android/build/generated/source/codegen/jni/OtaUpdaterSpec.h +24 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/ComponentDescriptors.cpp +22 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/ComponentDescriptors.h +24 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/EventEmitters.cpp +16 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/EventEmitters.h +17 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/OtaUpdaterSpecJSI.h +19 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/Props.cpp +19 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/Props.h +18 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/ShadowNodes.cpp +17 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/ShadowNodes.h +23 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/States.cpp +16 -0
- package/android/build/generated/source/codegen/jni/react/renderer/components/OtaUpdaterSpec/States.h +20 -0
- package/android/build/generated/source/codegen/schema.json +1 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +27 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
- package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
- package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +1 -0
- package/android/build/intermediates/compiled_local_resources/debug/compileDebugLibraryResources/out/xml_ota_file_paths.xml.flat +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +2 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
- package/android/build/intermediates/java_res/debug/processDebugJavaRes/out/META-INF/ota-updater_debug.kotlin_module +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/otaupdater/BuildConfig.class +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +3 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +43 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +27 -0
- package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
- package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
- package/android/build/intermediates/packaged_res/debug/packageDebugResources/xml/ota_file_paths.xml +6 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/META-INF/ota-updater_debug.kotlin_module +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/BuildConfig.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAApkInstallHelper.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAReactHostFactory.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTARestartActivity.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTARestartHelper.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAUpdaterModule$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAUpdaterModule$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAUpdaterModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAUpdaterPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAUpdaterStorage$NativeInfo.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAUpdaterStorage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/otaupdater/OTAZipExtractHelper.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +2 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +2 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +48 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/kotlin-classes/debug/META-INF/ota-updater_debug.kotlin_module +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAApkInstallHelper.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAReactHostFactory.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTARestartActivity.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTARestartHelper.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAUpdaterModule$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAUpdaterModule$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAUpdaterModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAUpdaterPackage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAUpdaterStorage$NativeInfo.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAUpdaterStorage.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/otaupdater/OTAZipExtractHelper.class +0 -0
- package/android/build.gradle +68 -0
- package/android/src/main/AndroidManifest.xml +21 -0
- package/android/src/main/java/com/otaupdater/OTAApkInstallHelper.kt +88 -0
- package/android/src/main/java/com/otaupdater/OTARestartActivity.kt +49 -0
- package/android/src/main/java/com/otaupdater/OTARestartHelper.kt +45 -0
- package/android/src/main/java/com/otaupdater/OTAUpdaterModule.kt +159 -0
- package/android/src/main/java/com/otaupdater/OTAUpdaterPackage.kt +16 -0
- package/android/src/main/java/com/otaupdater/OTAUpdaterStorage.kt +196 -0
- package/android/src/main/java/com/otaupdater/OTAZipExtractHelper.kt +62 -0
- package/android/src/main/res/xml/ota_file_paths.xml +6 -0
- package/android/src/reacthost76/java/com/otaupdater/OTAReactHostFactory.kt +84 -0
- package/ios/OTAUpdaterNative.h +4 -0
- package/ios/OTAUpdaterNative.m +110 -0
- package/lib/api.d.ts +1 -0
- package/lib/api.js +8 -0
- package/lib/config.d.ts +3 -0
- package/lib/config.js +11 -0
- package/lib/debug.d.ts +4 -0
- package/lib/debug.js +23 -0
- package/lib/index.d.ts +26 -0
- package/lib/index.js +74 -0
- package/lib/progress.d.ts +2 -0
- package/lib/progress.js +11 -0
- package/lib/projectConfig.d.ts +6 -0
- package/lib/projectConfig.js +47 -0
- package/lib/storage.d.ts +1 -0
- package/lib/storage.js +10 -0
- package/lib/sync.d.ts +50 -0
- package/lib/sync.js +728 -0
- package/lib/types.d.ts +97 -0
- package/lib/types.js +15 -0
- package/lib/ui/OTAUpdateModal.d.ts +8 -0
- package/lib/ui/OTAUpdateModal.js +138 -0
- package/lib/ui/OTAUpdateProvider.d.ts +3 -0
- package/lib/ui/OTAUpdateProvider.js +102 -0
- package/lib/zipExtract.d.ts +1 -0
- package/lib/zipExtract.js +113 -0
- package/package.json +46 -0
- package/react-native.config.js +12 -0
package/lib/sync.js
ADDED
|
@@ -0,0 +1,728 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.defaultMessages = void 0;
|
|
7
|
+
exports.getProgressState = getProgressState;
|
|
8
|
+
exports.subscribeProgress = subscribeProgress;
|
|
9
|
+
exports.hideProgress = hideProgress;
|
|
10
|
+
exports.getMessageForStatus = getMessageForStatus;
|
|
11
|
+
exports.getModalTitle = getModalTitle;
|
|
12
|
+
exports.delay = delay;
|
|
13
|
+
exports.getStoredBundleMeta = getStoredBundleMeta;
|
|
14
|
+
exports.setStoredBundleMeta = setStoredBundleMeta;
|
|
15
|
+
exports.getClientUniqueId = getClientUniqueId;
|
|
16
|
+
exports.clearStoredBundleMeta = clearStoredBundleMeta;
|
|
17
|
+
exports.markRestartPending = markRestartPending;
|
|
18
|
+
exports.shouldSkipSyncAfterRestart = shouldSkipSyncAfterRestart;
|
|
19
|
+
exports.getDeviceAbi = getDeviceAbi;
|
|
20
|
+
exports.checkForUpdate = checkForUpdate;
|
|
21
|
+
exports.getBundleReleaseDir = getBundleReleaseDir;
|
|
22
|
+
exports.getBundleFilePath = getBundleFilePath;
|
|
23
|
+
exports.getApkFilePath = getApkFilePath;
|
|
24
|
+
exports.downloadBundle = downloadBundle;
|
|
25
|
+
exports.verifyBundleHash = verifyBundleHash;
|
|
26
|
+
exports.isSyncInProgress = isSyncInProgress;
|
|
27
|
+
exports.restartApp = restartApp;
|
|
28
|
+
exports.installApk = installApk;
|
|
29
|
+
exports.resumePendingApkInstall = resumePendingApkInstall;
|
|
30
|
+
exports.sync = sync;
|
|
31
|
+
exports.getInstalledBundlePath = getInstalledBundlePath;
|
|
32
|
+
exports.clearUpdate = clearUpdate;
|
|
33
|
+
exports.notifyAppReady = notifyAppReady;
|
|
34
|
+
const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
|
|
35
|
+
const react_native_1 = require("react-native");
|
|
36
|
+
const react_native_device_info_1 = __importDefault(require("react-native-device-info"));
|
|
37
|
+
const config_1 = require("./config");
|
|
38
|
+
const zipExtract_1 = require("./zipExtract");
|
|
39
|
+
const types_1 = require("./types");
|
|
40
|
+
const initialProgressState = {
|
|
41
|
+
visible: false,
|
|
42
|
+
status: types_1.SyncStatus.UP_TO_DATE,
|
|
43
|
+
progress: 0,
|
|
44
|
+
message: '',
|
|
45
|
+
};
|
|
46
|
+
let progressState = { ...initialProgressState };
|
|
47
|
+
const progressListeners = new Set();
|
|
48
|
+
function getProgressState() {
|
|
49
|
+
return progressState;
|
|
50
|
+
}
|
|
51
|
+
function subscribeProgress(listener) {
|
|
52
|
+
progressListeners.add(listener);
|
|
53
|
+
return () => progressListeners.delete(listener);
|
|
54
|
+
}
|
|
55
|
+
function setProgressState(partial) {
|
|
56
|
+
progressState = { ...progressState, ...partial };
|
|
57
|
+
progressListeners.forEach((listener) => listener(progressState));
|
|
58
|
+
}
|
|
59
|
+
function hideProgress() {
|
|
60
|
+
progressState = { ...initialProgressState };
|
|
61
|
+
progressListeners.forEach((listener) => listener(progressState));
|
|
62
|
+
}
|
|
63
|
+
function shouldShowModalForStatus(status) {
|
|
64
|
+
return (status === types_1.SyncStatus.DOWNLOADING ||
|
|
65
|
+
status === types_1.SyncStatus.RESTARTING ||
|
|
66
|
+
status === types_1.SyncStatus.ERROR);
|
|
67
|
+
}
|
|
68
|
+
exports.defaultMessages = {
|
|
69
|
+
title: 'به\u200cروزرسانی برنامه',
|
|
70
|
+
checking: 'در حال بررسی به\u200cروزرسانی...',
|
|
71
|
+
downloading: 'در حال دانلود به\u200cروزرسانی...',
|
|
72
|
+
installing: 'در حال نصب به\u200cروزرسانی...',
|
|
73
|
+
restarting: 'در حال راه\u200cاندازی مجدد...',
|
|
74
|
+
error: 'خطا در به\u200cروزرسانی',
|
|
75
|
+
upToDate: 'برنامه به\u200cروز است',
|
|
76
|
+
};
|
|
77
|
+
function getMessageForStatus(status, messages = {}) {
|
|
78
|
+
const m = { ...exports.defaultMessages, ...messages };
|
|
79
|
+
switch (status) {
|
|
80
|
+
case types_1.SyncStatus.CHECKING:
|
|
81
|
+
return m.checking;
|
|
82
|
+
case types_1.SyncStatus.DOWNLOADING:
|
|
83
|
+
return m.downloading;
|
|
84
|
+
case types_1.SyncStatus.INSTALLING:
|
|
85
|
+
return m.installing;
|
|
86
|
+
case types_1.SyncStatus.RESTARTING:
|
|
87
|
+
return m.restarting;
|
|
88
|
+
case types_1.SyncStatus.ERROR:
|
|
89
|
+
return m.error;
|
|
90
|
+
default:
|
|
91
|
+
return m.upToDate;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function getModalTitle(messages = {}) {
|
|
95
|
+
const m = { ...exports.defaultMessages, ...messages };
|
|
96
|
+
return m.title;
|
|
97
|
+
}
|
|
98
|
+
function delay(ms) {
|
|
99
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
100
|
+
}
|
|
101
|
+
function showProgress(status, progress, message, extra) {
|
|
102
|
+
if (progressState.visible &&
|
|
103
|
+
progressState.status === status &&
|
|
104
|
+
status === types_1.SyncStatus.DOWNLOADING) {
|
|
105
|
+
setProgressState({
|
|
106
|
+
progress,
|
|
107
|
+
message,
|
|
108
|
+
error: undefined,
|
|
109
|
+
...extra,
|
|
110
|
+
});
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
setProgressState({
|
|
114
|
+
visible: true,
|
|
115
|
+
status,
|
|
116
|
+
progress,
|
|
117
|
+
message,
|
|
118
|
+
error: undefined,
|
|
119
|
+
...extra,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
const STORAGE_KEY = '@appsonair.ir/bundle-meta';
|
|
123
|
+
const CLIENT_ID_KEY = '@appsonair.ir/client-id';
|
|
124
|
+
const NATIVE_VERSION_KEY = '@appsonair.ir/native-version';
|
|
125
|
+
const NATIVE_BUILD_KEY = '@appsonair.ir/native-build';
|
|
126
|
+
const RESTART_COOLDOWN_KEY = '@appsonair.ir/last-restart';
|
|
127
|
+
const RESTART_COOLDOWN_MS = 15000;
|
|
128
|
+
async function getStoredBundleMeta() {
|
|
129
|
+
const raw = await async_storage_1.default.getItem(STORAGE_KEY);
|
|
130
|
+
if (!raw)
|
|
131
|
+
return null;
|
|
132
|
+
try {
|
|
133
|
+
return JSON.parse(raw);
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function setStoredBundleMeta(meta) {
|
|
140
|
+
await async_storage_1.default.setItem(STORAGE_KEY, JSON.stringify(meta));
|
|
141
|
+
}
|
|
142
|
+
async function getClientUniqueId() {
|
|
143
|
+
let id = await async_storage_1.default.getItem(CLIENT_ID_KEY);
|
|
144
|
+
if (!id) {
|
|
145
|
+
id = `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
146
|
+
await async_storage_1.default.setItem(CLIENT_ID_KEY, id);
|
|
147
|
+
}
|
|
148
|
+
return id;
|
|
149
|
+
}
|
|
150
|
+
async function clearStoredBundleMeta() {
|
|
151
|
+
await async_storage_1.default.removeItem(STORAGE_KEY);
|
|
152
|
+
}
|
|
153
|
+
async function markRestartPending() {
|
|
154
|
+
await async_storage_1.default.setItem(RESTART_COOLDOWN_KEY, String(Date.now()));
|
|
155
|
+
}
|
|
156
|
+
async function shouldSkipSyncAfterRestart() {
|
|
157
|
+
const raw = await async_storage_1.default.getItem(RESTART_COOLDOWN_KEY);
|
|
158
|
+
if (!raw)
|
|
159
|
+
return false;
|
|
160
|
+
const elapsed = Date.now() - parseInt(raw, 10);
|
|
161
|
+
if (elapsed >= RESTART_COOLDOWN_MS) {
|
|
162
|
+
await async_storage_1.default.removeItem(RESTART_COOLDOWN_KEY);
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
return elapsed < 3000;
|
|
166
|
+
}
|
|
167
|
+
/** Drop stale JS bundle after native version/build upgrade so OTA can resume. */
|
|
168
|
+
async function clearStaleBundleAfterNativeUpgrade() {
|
|
169
|
+
const currentVersion = react_native_device_info_1.default.getVersion();
|
|
170
|
+
const currentBuild = react_native_1.Platform.OS === 'android' ? react_native_device_info_1.default.getBuildNumber() : undefined;
|
|
171
|
+
const [storedVersion, storedBuild, meta] = await Promise.all([
|
|
172
|
+
async_storage_1.default.getItem(NATIVE_VERSION_KEY),
|
|
173
|
+
react_native_1.Platform.OS === 'android'
|
|
174
|
+
? async_storage_1.default.getItem(NATIVE_BUILD_KEY)
|
|
175
|
+
: Promise.resolve(null),
|
|
176
|
+
getStoredBundleMeta(),
|
|
177
|
+
]);
|
|
178
|
+
const versionChanged = storedVersion != null && storedVersion !== currentVersion;
|
|
179
|
+
const buildChanged = react_native_1.Platform.OS === 'android' &&
|
|
180
|
+
storedBuild != null &&
|
|
181
|
+
currentBuild != null &&
|
|
182
|
+
storedBuild !== currentBuild;
|
|
183
|
+
const firstRunWithStaleBundle = storedVersion == null && meta != null;
|
|
184
|
+
if (versionChanged || buildChanged || firstRunWithStaleBundle) {
|
|
185
|
+
console.log(`[OTA] Native version changed (${storedVersion ?? 'unknown'} → ${currentVersion}` +
|
|
186
|
+
(buildChanged ? `, build ${storedBuild} → ${currentBuild}` : '') +
|
|
187
|
+
'); clearing stale JS bundle.');
|
|
188
|
+
await clearUpdate();
|
|
189
|
+
}
|
|
190
|
+
await async_storage_1.default.setItem(NATIVE_VERSION_KEY, currentVersion);
|
|
191
|
+
if (react_native_1.Platform.OS === 'android' && currentBuild != null) {
|
|
192
|
+
await async_storage_1.default.setItem(NATIVE_BUILD_KEY, currentBuild);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function getDeviceAbi() {
|
|
196
|
+
if (react_native_1.Platform.OS !== 'android')
|
|
197
|
+
return undefined;
|
|
198
|
+
if (OTAUpdaterNative?.getDeviceAbi) {
|
|
199
|
+
try {
|
|
200
|
+
const abi = await OTAUpdaterNative.getDeviceAbi();
|
|
201
|
+
return typeof abi === 'string' ? abi : undefined;
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return undefined;
|
|
208
|
+
}
|
|
209
|
+
async function checkForUpdate(serverUrl, deploymentKey, appVersion, label, packageHash, clientUniqueId, buildNumber, deviceAbi) {
|
|
210
|
+
const baseUrl = serverUrl.replace(/\/$/, '');
|
|
211
|
+
const response = await fetch(`${baseUrl}/api/update-check`, {
|
|
212
|
+
method: 'POST',
|
|
213
|
+
headers: {
|
|
214
|
+
'Content-Type': 'application/json',
|
|
215
|
+
'X-Deployment-Key': deploymentKey,
|
|
216
|
+
},
|
|
217
|
+
body: JSON.stringify({
|
|
218
|
+
appVersion,
|
|
219
|
+
label,
|
|
220
|
+
packageHash,
|
|
221
|
+
clientUniqueId,
|
|
222
|
+
buildNumber,
|
|
223
|
+
deviceAbi,
|
|
224
|
+
}),
|
|
225
|
+
});
|
|
226
|
+
if (!response.ok) {
|
|
227
|
+
const text = await response.text();
|
|
228
|
+
throw new Error(`Update check failed (${response.status}): ${text}`);
|
|
229
|
+
}
|
|
230
|
+
return response.json();
|
|
231
|
+
}
|
|
232
|
+
function getBundleReleaseDir(label) {
|
|
233
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
234
|
+
const dirs = ReactNativeBlobUtil.fs.dirs;
|
|
235
|
+
return `${dirs.DocumentDir}/ota-updates/${label}`;
|
|
236
|
+
}
|
|
237
|
+
function getLegacyBundleFilePath(label) {
|
|
238
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
239
|
+
return `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota-updates/${label}.bundle`;
|
|
240
|
+
}
|
|
241
|
+
function getBundleFilePath(label) {
|
|
242
|
+
const bundleName = react_native_1.Platform.OS === 'ios' ? 'main.jsbundle' : 'index.android.bundle';
|
|
243
|
+
return `${getBundleReleaseDir(label)}/${bundleName}`;
|
|
244
|
+
}
|
|
245
|
+
function getBundleZipPath(label) {
|
|
246
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
247
|
+
const dirs = ReactNativeBlobUtil.fs.dirs;
|
|
248
|
+
return `${dirs.DocumentDir}/ota-updates/${label}.zip`;
|
|
249
|
+
}
|
|
250
|
+
async function removePathRecursive(path) {
|
|
251
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
252
|
+
const exists = await ReactNativeBlobUtil.fs.exists(path);
|
|
253
|
+
if (!exists) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
try {
|
|
257
|
+
const stat = await ReactNativeBlobUtil.fs.stat(path);
|
|
258
|
+
if (stat.type === 'directory') {
|
|
259
|
+
const entries = await ReactNativeBlobUtil.fs.ls(path);
|
|
260
|
+
for (const entry of entries) {
|
|
261
|
+
await removePathRecursive(`${path}/${entry}`);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// Fall through to unlink.
|
|
267
|
+
}
|
|
268
|
+
await ReactNativeBlobUtil.fs.unlink(path);
|
|
269
|
+
}
|
|
270
|
+
async function isZipArchive(filePath) {
|
|
271
|
+
if (filePath.endsWith('.zip')) {
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
275
|
+
if (typeof ReactNativeBlobUtil.fs.slice !== 'function') {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
const prefixPath = `${filePath}.magic`;
|
|
279
|
+
try {
|
|
280
|
+
await ReactNativeBlobUtil.fs.slice(filePath, prefixPath, 0, 4);
|
|
281
|
+
const b64 = await ReactNativeBlobUtil.fs.readFile(prefixPath, 'base64');
|
|
282
|
+
await ReactNativeBlobUtil.fs.unlink(prefixPath);
|
|
283
|
+
const bytes = globalThis.atob
|
|
284
|
+
? globalThis.atob(b64)
|
|
285
|
+
: Buffer.from(b64, 'base64').toString('binary');
|
|
286
|
+
return bytes.charCodeAt(0) === 0x50 && bytes.charCodeAt(1) === 0x4b;
|
|
287
|
+
}
|
|
288
|
+
catch {
|
|
289
|
+
try {
|
|
290
|
+
const prefixExists = await ReactNativeBlobUtil.fs.exists(prefixPath);
|
|
291
|
+
if (prefixExists) {
|
|
292
|
+
await ReactNativeBlobUtil.fs.unlink(prefixPath);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
// Ignore cleanup errors.
|
|
297
|
+
}
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
async function shouldExtractZipPackage(downloadedPath, packageFormat) {
|
|
302
|
+
if (packageFormat === 'zip') {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
return isZipArchive(downloadedPath);
|
|
306
|
+
}
|
|
307
|
+
async function resolveBundlePathInDir(releaseDir) {
|
|
308
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
309
|
+
const candidates = react_native_1.Platform.OS === 'ios'
|
|
310
|
+
? ['main.jsbundle', 'index.ios.bundle']
|
|
311
|
+
: ['index.android.bundle'];
|
|
312
|
+
for (const name of candidates) {
|
|
313
|
+
const path = `${releaseDir}/${name}`;
|
|
314
|
+
if (await ReactNativeBlobUtil.fs.exists(path)) {
|
|
315
|
+
return path;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
try {
|
|
319
|
+
const entries = await ReactNativeBlobUtil.fs.ls(releaseDir);
|
|
320
|
+
for (const entry of entries) {
|
|
321
|
+
const entryPath = `${releaseDir}/${entry}`;
|
|
322
|
+
const entryStat = await ReactNativeBlobUtil.fs.stat(entryPath);
|
|
323
|
+
if (entryStat.type !== 'directory') {
|
|
324
|
+
continue;
|
|
325
|
+
}
|
|
326
|
+
for (const name of candidates) {
|
|
327
|
+
const path = `${entryPath}/${name}`;
|
|
328
|
+
if (await ReactNativeBlobUtil.fs.exists(path)) {
|
|
329
|
+
return path;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// Ignore listing errors and fall through.
|
|
336
|
+
}
|
|
337
|
+
throw new Error(`No JS bundle found in ${releaseDir}`);
|
|
338
|
+
}
|
|
339
|
+
async function extractBundleUpdate(label, zipPath) {
|
|
340
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
341
|
+
const releaseDir = getBundleReleaseDir(label);
|
|
342
|
+
await removePathRecursive(releaseDir);
|
|
343
|
+
await ReactNativeBlobUtil.fs.mkdir(releaseDir);
|
|
344
|
+
await (0, zipExtract_1.extractZipToDirectory)(zipPath, releaseDir);
|
|
345
|
+
const zipExists = await ReactNativeBlobUtil.fs.exists(zipPath);
|
|
346
|
+
if (zipExists) {
|
|
347
|
+
await ReactNativeBlobUtil.fs.unlink(zipPath);
|
|
348
|
+
}
|
|
349
|
+
return resolveBundlePathInDir(releaseDir);
|
|
350
|
+
}
|
|
351
|
+
function getApkFilePath(label) {
|
|
352
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
353
|
+
const dirs = ReactNativeBlobUtil.fs.dirs;
|
|
354
|
+
return `${dirs.DocumentDir}/ota-updates/${label}.apk`;
|
|
355
|
+
}
|
|
356
|
+
function getBundleDirectory() {
|
|
357
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
358
|
+
return `${ReactNativeBlobUtil.fs.dirs.DocumentDir}/ota-updates`;
|
|
359
|
+
}
|
|
360
|
+
async function ensureBundleDirectory() {
|
|
361
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
362
|
+
const dir = getBundleDirectory();
|
|
363
|
+
const exists = await ReactNativeBlobUtil.fs.exists(dir);
|
|
364
|
+
if (!exists) {
|
|
365
|
+
await ReactNativeBlobUtil.fs.mkdir(dir);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
async function resolveDownloadSize(downloadUrl, deploymentKey, expectedSize, deviceAbi) {
|
|
369
|
+
if (expectedSize && expectedSize > 0) {
|
|
370
|
+
return expectedSize;
|
|
371
|
+
}
|
|
372
|
+
try {
|
|
373
|
+
const headers = {
|
|
374
|
+
'X-Deployment-Key': deploymentKey,
|
|
375
|
+
};
|
|
376
|
+
if (deviceAbi) {
|
|
377
|
+
headers['X-Device-Abi'] = deviceAbi;
|
|
378
|
+
}
|
|
379
|
+
const response = await fetch(downloadUrl, {
|
|
380
|
+
method: 'HEAD',
|
|
381
|
+
headers,
|
|
382
|
+
});
|
|
383
|
+
if (!response.ok) {
|
|
384
|
+
return expectedSize ?? 0;
|
|
385
|
+
}
|
|
386
|
+
const contentLength = response.headers.get('content-length');
|
|
387
|
+
if (contentLength) {
|
|
388
|
+
const parsed = parseInt(contentLength, 10);
|
|
389
|
+
if (parsed > 0)
|
|
390
|
+
return parsed;
|
|
391
|
+
}
|
|
392
|
+
const fallbackLength = response.headers.get('x-content-length');
|
|
393
|
+
if (fallbackLength) {
|
|
394
|
+
const parsed = parseInt(fallbackLength, 10);
|
|
395
|
+
if (parsed > 0)
|
|
396
|
+
return parsed;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
catch {
|
|
400
|
+
// HEAD may be blocked by some proxies; fall back to update-check size.
|
|
401
|
+
}
|
|
402
|
+
return expectedSize ?? 0;
|
|
403
|
+
}
|
|
404
|
+
async function downloadBundle(downloadUrl, deploymentKey, label, expectedSize, onProgress, extension = 'bundle', deviceAbi, packageFormat = 'bundle', expectedHash) {
|
|
405
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
406
|
+
const isZipBundle = extension === 'bundle' && packageFormat === 'zip';
|
|
407
|
+
const destPath = isZipBundle
|
|
408
|
+
? getBundleZipPath(label)
|
|
409
|
+
: extension === 'apk'
|
|
410
|
+
? getApkFilePath(label)
|
|
411
|
+
: getLegacyBundleFilePath(label);
|
|
412
|
+
const totalBytes = await resolveDownloadSize(downloadUrl, deploymentKey, expectedSize, deviceAbi);
|
|
413
|
+
await ensureBundleDirectory();
|
|
414
|
+
if (isZipBundle) {
|
|
415
|
+
await removePathRecursive(getBundleReleaseDir(label));
|
|
416
|
+
}
|
|
417
|
+
const destExists = await ReactNativeBlobUtil.fs.exists(destPath);
|
|
418
|
+
if (destExists) {
|
|
419
|
+
await ReactNativeBlobUtil.fs.unlink(destPath);
|
|
420
|
+
}
|
|
421
|
+
const task = ReactNativeBlobUtil.config({
|
|
422
|
+
path: destPath,
|
|
423
|
+
fileCache: false,
|
|
424
|
+
overwrite: true,
|
|
425
|
+
}).fetch('GET', downloadUrl, {
|
|
426
|
+
'X-Deployment-Key': deploymentKey,
|
|
427
|
+
...(deviceAbi ? { 'X-Device-Abi': deviceAbi } : {}),
|
|
428
|
+
});
|
|
429
|
+
const reportDownloadProgress = (received, total) => {
|
|
430
|
+
if (!onProgress)
|
|
431
|
+
return;
|
|
432
|
+
const resolvedTotal = total > 0 ? total : totalBytes;
|
|
433
|
+
if (resolvedTotal <= 0)
|
|
434
|
+
return;
|
|
435
|
+
onProgress(Math.min(Math.max(received / resolvedTotal, 0), 0.99));
|
|
436
|
+
};
|
|
437
|
+
let pollTimer = null;
|
|
438
|
+
if (onProgress && totalBytes > 0) {
|
|
439
|
+
pollTimer = setInterval(async () => {
|
|
440
|
+
try {
|
|
441
|
+
const exists = await ReactNativeBlobUtil.fs.exists(destPath);
|
|
442
|
+
if (!exists)
|
|
443
|
+
return;
|
|
444
|
+
const stat = await ReactNativeBlobUtil.fs.stat(destPath);
|
|
445
|
+
reportDownloadProgress(stat.size, totalBytes);
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
// Ignore polling errors while the file is being written.
|
|
449
|
+
}
|
|
450
|
+
}, 150);
|
|
451
|
+
}
|
|
452
|
+
if (onProgress) {
|
|
453
|
+
task.progress({ interval: 100, count: 10 }, (received, total) => {
|
|
454
|
+
reportDownloadProgress(received, total);
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
try {
|
|
458
|
+
const response = await task;
|
|
459
|
+
if (onProgress) {
|
|
460
|
+
onProgress(1);
|
|
461
|
+
}
|
|
462
|
+
const downloadedPath = String(response.path()).replace(/^file:\/\//, '');
|
|
463
|
+
if (downloadedPath !== destPath) {
|
|
464
|
+
await ReactNativeBlobUtil.fs.cp(downloadedPath, destPath);
|
|
465
|
+
}
|
|
466
|
+
const stat = await ReactNativeBlobUtil.fs.stat(destPath);
|
|
467
|
+
const minSize = extension === 'apk' ? 1024 * 100 : 1024;
|
|
468
|
+
if (!stat || stat.size < minSize) {
|
|
469
|
+
throw new Error(`Downloaded file is too small (${stat?.size ?? 0} bytes)`);
|
|
470
|
+
}
|
|
471
|
+
if (expectedHash) {
|
|
472
|
+
const valid = await verifyBundleHash(destPath, expectedHash);
|
|
473
|
+
if (!valid) {
|
|
474
|
+
throw new Error('Package hash verification failed');
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
if (extension === 'bundle' && (await shouldExtractZipPackage(destPath, packageFormat))) {
|
|
478
|
+
return extractBundleUpdate(label, destPath);
|
|
479
|
+
}
|
|
480
|
+
return destPath;
|
|
481
|
+
}
|
|
482
|
+
finally {
|
|
483
|
+
if (pollTimer) {
|
|
484
|
+
clearInterval(pollTimer);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
async function verifyBundleHash(filePath, expectedHash) {
|
|
489
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
490
|
+
const hash = await ReactNativeBlobUtil.fs.hash(filePath, 'sha256');
|
|
491
|
+
return hash.toLowerCase() === expectedHash.toLowerCase();
|
|
492
|
+
}
|
|
493
|
+
const { OTAUpdaterNative } = react_native_1.NativeModules;
|
|
494
|
+
let activeSync = null;
|
|
495
|
+
function isSyncInProgress() {
|
|
496
|
+
return activeSync !== null;
|
|
497
|
+
}
|
|
498
|
+
function shouldShowUI(options) {
|
|
499
|
+
const config = (0, config_1.getConfig)();
|
|
500
|
+
return options.showProgressUI ?? config?.showProgressUI ?? false;
|
|
501
|
+
}
|
|
502
|
+
function reportProgress(showUI, messages, onProgress, status, progress = 0, extra) {
|
|
503
|
+
onProgress?.(status, progress);
|
|
504
|
+
if (!showUI)
|
|
505
|
+
return;
|
|
506
|
+
// Silent phases — never show modal for check / install / up-to-date.
|
|
507
|
+
if (status === types_1.SyncStatus.CHECKING ||
|
|
508
|
+
status === types_1.SyncStatus.UP_TO_DATE ||
|
|
509
|
+
status === types_1.SyncStatus.UPDATE_IGNORED ||
|
|
510
|
+
status === types_1.SyncStatus.INSTALLING) {
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
if (status === types_1.SyncStatus.ERROR) {
|
|
514
|
+
showProgress(status, progress, extra?.error ?? getMessageForStatus(status, messages), {
|
|
515
|
+
error: extra?.error,
|
|
516
|
+
...extra,
|
|
517
|
+
});
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
if (shouldShowModalForStatus(status)) {
|
|
521
|
+
showProgress(status, progress, getMessageForStatus(status, messages), extra);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
async function restartApp() {
|
|
525
|
+
if (OTAUpdaterNative?.restartApp) {
|
|
526
|
+
await OTAUpdaterNative.restartApp();
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
try {
|
|
530
|
+
const RNRestart = require('react-native-restart').default;
|
|
531
|
+
RNRestart.restart();
|
|
532
|
+
}
|
|
533
|
+
catch {
|
|
534
|
+
throw new Error('Cannot restart app. Install react-native-restart or link OTAUpdaterNative module.');
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
async function installApk(apkPath) {
|
|
538
|
+
if (!OTAUpdaterNative?.installApk) {
|
|
539
|
+
throw new Error('APK install is not available. Rebuild the Android app with OTAUpdaterNative linked.');
|
|
540
|
+
}
|
|
541
|
+
const result = await OTAUpdaterNative.installApk(apkPath);
|
|
542
|
+
return result === 'permission_required' ? 'permission_required' : 'started';
|
|
543
|
+
}
|
|
544
|
+
async function resumePendingApkInstall() {
|
|
545
|
+
if (OTAUpdaterNative?.retryPendingApkInstall) {
|
|
546
|
+
await OTAUpdaterNative.retryPendingApkInstall();
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
async function sync(options = {}, onProgress, messages) {
|
|
550
|
+
if (activeSync) {
|
|
551
|
+
return activeSync;
|
|
552
|
+
}
|
|
553
|
+
activeSync = performSync(options, onProgress, messages).finally(() => {
|
|
554
|
+
activeSync = null;
|
|
555
|
+
});
|
|
556
|
+
return activeSync;
|
|
557
|
+
}
|
|
558
|
+
async function performSync(options = {}, onProgress, messages) {
|
|
559
|
+
const config = (0, config_1.getConfig)();
|
|
560
|
+
if (!config) {
|
|
561
|
+
throw new Error('OTAUpdater.configure() must be called first');
|
|
562
|
+
}
|
|
563
|
+
if (await shouldSkipSyncAfterRestart()) {
|
|
564
|
+
return { status: types_1.SyncStatus.UP_TO_DATE };
|
|
565
|
+
}
|
|
566
|
+
const showUI = shouldShowUI(options);
|
|
567
|
+
try {
|
|
568
|
+
onProgress?.(types_1.SyncStatus.CHECKING, 0);
|
|
569
|
+
await clearStaleBundleAfterNativeUpgrade();
|
|
570
|
+
const meta = await getStoredBundleMeta();
|
|
571
|
+
const clientUniqueId = await getClientUniqueId();
|
|
572
|
+
const enableApkUpdates = options.enableApkUpdates ??
|
|
573
|
+
config.enableApkUpdates ??
|
|
574
|
+
react_native_1.Platform.OS === 'android';
|
|
575
|
+
const buildNumber = enableApkUpdates && react_native_1.Platform.OS === 'android'
|
|
576
|
+
? react_native_device_info_1.default.getBuildNumber()
|
|
577
|
+
: undefined;
|
|
578
|
+
const deviceAbi = enableApkUpdates && react_native_1.Platform.OS === 'android'
|
|
579
|
+
? await getDeviceAbi()
|
|
580
|
+
: undefined;
|
|
581
|
+
const update = await checkForUpdate(config.serverUrl, config.deploymentKey, react_native_device_info_1.default.getVersion(), meta?.label, meta?.packageHash, clientUniqueId, buildNumber, deviceAbi);
|
|
582
|
+
if (!update.updateAvailable || !update.downloadUrl || !update.label || !update.packageHash) {
|
|
583
|
+
if (update.reason === 'NATIVE_VERSION_MISMATCH') {
|
|
584
|
+
console.warn(`[OTA] Native version mismatch: device=${update.clientAppVersion ?? 'unknown'}, ` +
|
|
585
|
+
`release targets=${update.targetAppVersion ?? update.appVersion ?? 'unknown'}. ` +
|
|
586
|
+
'Redeploy with the correct --app-version (must match versionName / MARKETING_VERSION).');
|
|
587
|
+
}
|
|
588
|
+
if (showUI)
|
|
589
|
+
hideProgress();
|
|
590
|
+
onProgress?.(types_1.SyncStatus.UP_TO_DATE, 1);
|
|
591
|
+
return { status: types_1.SyncStatus.UP_TO_DATE };
|
|
592
|
+
}
|
|
593
|
+
if (update.updateType === 'apk') {
|
|
594
|
+
return performApkSync(update, showUI, messages, onProgress);
|
|
595
|
+
}
|
|
596
|
+
reportProgress(showUI, messages, onProgress, types_1.SyncStatus.DOWNLOADING, 0, {
|
|
597
|
+
label: update.label,
|
|
598
|
+
description: update.description,
|
|
599
|
+
});
|
|
600
|
+
const bundlePath = await downloadBundle(update.downloadUrl, config.deploymentKey, update.label, update.size, (p) => reportProgress(showUI, messages, onProgress, types_1.SyncStatus.DOWNLOADING, p, {
|
|
601
|
+
label: update.label,
|
|
602
|
+
description: update.description,
|
|
603
|
+
}), 'bundle', undefined, update.packageFormat ?? 'bundle', update.packageHash);
|
|
604
|
+
onProgress?.(types_1.SyncStatus.INSTALLING, 1);
|
|
605
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
606
|
+
const bundleExists = await ReactNativeBlobUtil.fs.exists(bundlePath);
|
|
607
|
+
if (!bundleExists) {
|
|
608
|
+
throw new Error(`Bundle file missing before install: ${bundlePath}`);
|
|
609
|
+
}
|
|
610
|
+
if (OTAUpdaterNative?.setBundlePath) {
|
|
611
|
+
await OTAUpdaterNative.setBundlePath(bundlePath);
|
|
612
|
+
}
|
|
613
|
+
await setStoredBundleMeta({
|
|
614
|
+
label: update.label,
|
|
615
|
+
packageHash: update.packageHash,
|
|
616
|
+
installedAt: new Date().toISOString(),
|
|
617
|
+
});
|
|
618
|
+
const installMode = options.installMode ?? config.installMode ?? 'immediate';
|
|
619
|
+
const shouldRestartNow = installMode === 'immediate' || update.isMandatory === true;
|
|
620
|
+
if (shouldRestartNow) {
|
|
621
|
+
reportProgress(showUI, messages, onProgress, types_1.SyncStatus.RESTARTING, 1, {
|
|
622
|
+
label: update.label,
|
|
623
|
+
description: update.description,
|
|
624
|
+
});
|
|
625
|
+
await markRestartPending();
|
|
626
|
+
await delay(300);
|
|
627
|
+
await restartApp();
|
|
628
|
+
return {
|
|
629
|
+
status: types_1.SyncStatus.UPDATE_INSTALLED,
|
|
630
|
+
label: update.label,
|
|
631
|
+
description: update.description,
|
|
632
|
+
};
|
|
633
|
+
}
|
|
634
|
+
if (showUI)
|
|
635
|
+
hideProgress();
|
|
636
|
+
return {
|
|
637
|
+
status: types_1.SyncStatus.UPDATE_INSTALLED,
|
|
638
|
+
label: update.label,
|
|
639
|
+
description: update.description,
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
catch (error) {
|
|
643
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
644
|
+
reportProgress(showUI, messages, onProgress, types_1.SyncStatus.ERROR, 0, {
|
|
645
|
+
error: err.message,
|
|
646
|
+
});
|
|
647
|
+
return {
|
|
648
|
+
status: types_1.SyncStatus.ERROR,
|
|
649
|
+
error: err,
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
async function performApkSync(update, showUI, messages, onProgress) {
|
|
654
|
+
if (!update.downloadUrl || !update.label || !update.packageHash) {
|
|
655
|
+
return { status: types_1.SyncStatus.UP_TO_DATE };
|
|
656
|
+
}
|
|
657
|
+
try {
|
|
658
|
+
reportProgress(showUI, messages, onProgress, types_1.SyncStatus.DOWNLOADING, 0, {
|
|
659
|
+
label: update.label,
|
|
660
|
+
description: update.description,
|
|
661
|
+
});
|
|
662
|
+
const apkPath = await downloadBundle(update.downloadUrl, (0, config_1.getConfig)().deploymentKey, update.label, update.size, (p) => reportProgress(showUI, messages, onProgress, types_1.SyncStatus.DOWNLOADING, p, {
|
|
663
|
+
label: update.label,
|
|
664
|
+
description: update.description,
|
|
665
|
+
}), 'apk', update.deviceAbi);
|
|
666
|
+
onProgress?.(types_1.SyncStatus.INSTALLING, 1);
|
|
667
|
+
const valid = await verifyBundleHash(apkPath, update.packageHash);
|
|
668
|
+
if (!valid) {
|
|
669
|
+
throw new Error('APK hash verification failed');
|
|
670
|
+
}
|
|
671
|
+
// Drop the OTA JS path before opening the installer so the new APK does not
|
|
672
|
+
// keep loading the previous bundle on first launch after install.
|
|
673
|
+
await clearUpdate();
|
|
674
|
+
const installResult = await installApk(apkPath);
|
|
675
|
+
if (installResult === 'permission_required') {
|
|
676
|
+
reportProgress(showUI, messages, onProgress, types_1.SyncStatus.INSTALLING, 1, {
|
|
677
|
+
label: update.label,
|
|
678
|
+
description: update.description,
|
|
679
|
+
});
|
|
680
|
+
return {
|
|
681
|
+
status: types_1.SyncStatus.APK_INSTALL_PENDING,
|
|
682
|
+
label: update.label,
|
|
683
|
+
description: update.description,
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
if (showUI)
|
|
687
|
+
hideProgress();
|
|
688
|
+
onProgress?.(types_1.SyncStatus.APK_INSTALL_PENDING, 1);
|
|
689
|
+
return {
|
|
690
|
+
status: types_1.SyncStatus.APK_INSTALL_PENDING,
|
|
691
|
+
label: update.label,
|
|
692
|
+
description: update.description,
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
catch (error) {
|
|
696
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
697
|
+
reportProgress(showUI, messages, onProgress, types_1.SyncStatus.ERROR, 0, {
|
|
698
|
+
error: err.message,
|
|
699
|
+
});
|
|
700
|
+
return {
|
|
701
|
+
status: types_1.SyncStatus.ERROR,
|
|
702
|
+
error: err,
|
|
703
|
+
};
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
async function getInstalledBundlePath() {
|
|
707
|
+
const meta = await getStoredBundleMeta();
|
|
708
|
+
if (!meta)
|
|
709
|
+
return null;
|
|
710
|
+
const ReactNativeBlobUtil = require('react-native-blob-util').default;
|
|
711
|
+
const candidates = [getBundleFilePath(meta.label), getLegacyBundleFilePath(meta.label)];
|
|
712
|
+
for (const path of candidates) {
|
|
713
|
+
const exists = await ReactNativeBlobUtil.fs.exists(path);
|
|
714
|
+
if (exists)
|
|
715
|
+
return path;
|
|
716
|
+
}
|
|
717
|
+
return null;
|
|
718
|
+
}
|
|
719
|
+
async function clearUpdate() {
|
|
720
|
+
await clearStoredBundleMeta();
|
|
721
|
+
if (OTAUpdaterNative?.clearBundlePath) {
|
|
722
|
+
await OTAUpdaterNative.clearBundlePath();
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
async function notifyAppReady() {
|
|
726
|
+
const meta = await getStoredBundleMeta();
|
|
727
|
+
return meta ? types_1.SyncStatus.UPDATE_INSTALLED : types_1.SyncStatus.UP_TO_DATE;
|
|
728
|
+
}
|