@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
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
package com.otaupdater
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.facebook.react.ReactApplication
|
|
5
|
+
import com.facebook.react.bridge.LifecycleEventListener
|
|
6
|
+
import com.facebook.react.bridge.Promise
|
|
7
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
9
|
+
import com.facebook.react.bridge.ReactMethod
|
|
10
|
+
import com.facebook.react.bridge.UiThreadUtil
|
|
11
|
+
import com.facebook.react.common.build.ReactBuildConfig
|
|
12
|
+
import java.io.File
|
|
13
|
+
|
|
14
|
+
class OTAUpdaterModule(private val reactContext: ReactApplicationContext) :
|
|
15
|
+
ReactContextBaseJavaModule(reactContext) {
|
|
16
|
+
|
|
17
|
+
init {
|
|
18
|
+
reactContext.addLifecycleEventListener(
|
|
19
|
+
object : LifecycleEventListener {
|
|
20
|
+
override fun onHostResume() {
|
|
21
|
+
UiThreadUtil.runOnUiThread {
|
|
22
|
+
OTAApkInstallHelper.retryPendingInstall(reactContext)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
override fun onHostPause() {}
|
|
27
|
+
|
|
28
|
+
override fun onHostDestroy() {}
|
|
29
|
+
},
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
companion object {
|
|
34
|
+
@JvmStatic
|
|
35
|
+
fun getBundlePath(context: Context): String? =
|
|
36
|
+
OTAUpdaterStorage.getBundlePath(context)
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* RN 0.76+ exposes ReactHost with setBundleSource(). Use reflection so RN 0.74/0.75 still compile.
|
|
40
|
+
*/
|
|
41
|
+
@JvmStatic
|
|
42
|
+
private fun tryHotReloadBundle(app: ReactApplication, bundlePath: String): Boolean {
|
|
43
|
+
return try {
|
|
44
|
+
val reactHost =
|
|
45
|
+
try {
|
|
46
|
+
app.javaClass.getMethod("getReactHost").invoke(app)
|
|
47
|
+
} catch (_: Exception) {
|
|
48
|
+
null
|
|
49
|
+
} ?: return false
|
|
50
|
+
|
|
51
|
+
val method = reactHost.javaClass.getMethod("setBundleSource", String::class.java)
|
|
52
|
+
method.invoke(reactHost, bundlePath)
|
|
53
|
+
true
|
|
54
|
+
} catch (_: Exception) {
|
|
55
|
+
false
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
override fun getName(): String = "OTAUpdaterNative"
|
|
61
|
+
|
|
62
|
+
@ReactMethod
|
|
63
|
+
fun setBundlePath(path: String, promise: Promise) {
|
|
64
|
+
val normalizedPath = path.removePrefix("file://")
|
|
65
|
+
val file = File(normalizedPath)
|
|
66
|
+
if (!OTAUpdaterStorage.isValidBundle(file)) {
|
|
67
|
+
promise.reject("EINVAL", "Bundle file is missing or invalid: $normalizedPath")
|
|
68
|
+
return
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
val saved = OTAUpdaterStorage.setBundlePath(reactContext, normalizedPath)
|
|
72
|
+
if (!saved) {
|
|
73
|
+
promise.reject("ESTORAGE", "Failed to persist bundle path")
|
|
74
|
+
return
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
promise.resolve(normalizedPath)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
@ReactMethod
|
|
81
|
+
fun getBundlePath(promise: Promise) {
|
|
82
|
+
promise.resolve(OTAUpdaterStorage.getBundlePath(reactContext))
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@ReactMethod
|
|
86
|
+
fun clearBundlePath(promise: Promise) {
|
|
87
|
+
OTAUpdaterStorage.clearBundlePath(reactContext)
|
|
88
|
+
promise.resolve(true)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@ReactMethod
|
|
92
|
+
fun getDeviceAbi(promise: Promise) {
|
|
93
|
+
try {
|
|
94
|
+
val abis = android.os.Build.SUPPORTED_ABIS
|
|
95
|
+
promise.resolve(abis.firstOrNull() ?: "unknown")
|
|
96
|
+
} catch (e: Exception) {
|
|
97
|
+
promise.reject("EABI", e.message, e)
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@ReactMethod
|
|
102
|
+
fun installApk(path: String, promise: Promise) {
|
|
103
|
+
UiThreadUtil.runOnUiThread {
|
|
104
|
+
try {
|
|
105
|
+
val result = OTAApkInstallHelper.install(reactContext, path)
|
|
106
|
+
promise.resolve(result)
|
|
107
|
+
} catch (e: Exception) {
|
|
108
|
+
promise.reject("EINSTALL", e.message, e)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
@ReactMethod
|
|
114
|
+
fun retryPendingApkInstall(promise: Promise) {
|
|
115
|
+
UiThreadUtil.runOnUiThread {
|
|
116
|
+
try {
|
|
117
|
+
OTAApkInstallHelper.retryPendingInstall(reactContext)
|
|
118
|
+
promise.resolve(true)
|
|
119
|
+
} catch (e: Exception) {
|
|
120
|
+
promise.reject("EINSTALL", e.message, e)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@ReactMethod
|
|
126
|
+
fun extractZipArchive(zipPath: String, destDir: String, promise: Promise) {
|
|
127
|
+
Thread {
|
|
128
|
+
try {
|
|
129
|
+
OTAZipExtractHelper.extract(zipPath, destDir)
|
|
130
|
+
promise.resolve(destDir.removePrefix("file://"))
|
|
131
|
+
} catch (e: Exception) {
|
|
132
|
+
promise.reject("EUNZIP", e.message, e)
|
|
133
|
+
}
|
|
134
|
+
}.start()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
@ReactMethod
|
|
138
|
+
fun restartApp(promise: Promise) {
|
|
139
|
+
UiThreadUtil.runOnUiThread {
|
|
140
|
+
try {
|
|
141
|
+
val normalizedPath = OTAUpdaterStorage.getBundlePath(reactContext)
|
|
142
|
+
|
|
143
|
+
// Debug hot-reload is RN 0.76+ only; RN 0.74 always process-restarts.
|
|
144
|
+
if (ReactBuildConfig.DEBUG && normalizedPath != null) {
|
|
145
|
+
val app = reactContext.applicationContext as? ReactApplication
|
|
146
|
+
if (app != null && tryHotReloadBundle(app, normalizedPath)) {
|
|
147
|
+
promise.resolve("reloaded")
|
|
148
|
+
return@runOnUiThread
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
OTARestartHelper.triggerRebirth(reactContext.applicationContext)
|
|
153
|
+
promise.resolve("restarted")
|
|
154
|
+
} catch (e: Exception) {
|
|
155
|
+
promise.reject("ERESTART", e.message, e)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
package com.otaupdater
|
|
2
|
+
|
|
3
|
+
import com.facebook.react.ReactPackage
|
|
4
|
+
import com.facebook.react.bridge.NativeModule
|
|
5
|
+
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.uimanager.ViewManager
|
|
7
|
+
|
|
8
|
+
class OTAUpdaterPackage : ReactPackage {
|
|
9
|
+
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
|
|
10
|
+
return listOf(OTAUpdaterModule(reactContext))
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
|
|
14
|
+
return emptyList()
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
package com.otaupdater
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.content.pm.PackageManager
|
|
5
|
+
import android.os.Build
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import java.io.File
|
|
8
|
+
|
|
9
|
+
object OTAUpdaterStorage {
|
|
10
|
+
private const val PREFS_NAME = "ota_updater"
|
|
11
|
+
private const val KEY_BUNDLE_PATH = "bundle_path"
|
|
12
|
+
private const val KEY_NATIVE_VERSION = "native_version"
|
|
13
|
+
private const val KEY_NATIVE_BUILD = "native_build"
|
|
14
|
+
private const val KEY_PENDING_APK_PATH = "pending_apk_path"
|
|
15
|
+
private const val MIN_BUNDLE_BYTES = 1024L
|
|
16
|
+
private const val MIN_APK_BYTES = 1024L * 100
|
|
17
|
+
private const val TAG = "OTAUpdater"
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Returns the OTA JS bundle path, or null after clearing a stale path when the
|
|
21
|
+
* installed APK versionName / versionCode changed. Must run before RN loads JS
|
|
22
|
+
* so a post-APK install does not keep serving the previous OTA bundle.
|
|
23
|
+
*/
|
|
24
|
+
fun getBundlePath(context: Context): String? {
|
|
25
|
+
clearStaleBundleAfterNativeUpgrade(context)
|
|
26
|
+
|
|
27
|
+
val path =
|
|
28
|
+
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
29
|
+
.getString(KEY_BUNDLE_PATH, null)
|
|
30
|
+
?: return null
|
|
31
|
+
|
|
32
|
+
val file = File(normalizePath(path))
|
|
33
|
+
if (!isValidBundle(file)) {
|
|
34
|
+
clearBundlePath(context)
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return file.absolutePath
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
fun setBundlePath(context: Context, path: String): Boolean {
|
|
42
|
+
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
43
|
+
.edit()
|
|
44
|
+
.putString(KEY_BUNDLE_PATH, normalizePath(path))
|
|
45
|
+
.commit()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
fun clearBundlePath(context: Context) {
|
|
49
|
+
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
50
|
+
.edit()
|
|
51
|
+
.remove(KEY_BUNDLE_PATH)
|
|
52
|
+
.commit()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Drop a persisted OTA bundle when the native binary changed (new APK install).
|
|
57
|
+
* Safe to call from Application / getJSBundleFile before React Native starts.
|
|
58
|
+
*/
|
|
59
|
+
fun clearStaleBundleAfterNativeUpgrade(context: Context) {
|
|
60
|
+
val current = readInstalledNativeInfo(context) ?: return
|
|
61
|
+
val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
62
|
+
val storedVersion = prefs.getString(KEY_NATIVE_VERSION, null)
|
|
63
|
+
val storedBuild = if (prefs.contains(KEY_NATIVE_BUILD)) {
|
|
64
|
+
prefs.getLong(KEY_NATIVE_BUILD, -1L)
|
|
65
|
+
} else {
|
|
66
|
+
null
|
|
67
|
+
}
|
|
68
|
+
val hasBundlePath = prefs.contains(KEY_BUNDLE_PATH)
|
|
69
|
+
|
|
70
|
+
val versionChanged = storedVersion != null && storedVersion != current.versionName
|
|
71
|
+
val buildChanged = storedBuild != null && storedBuild != current.versionCode
|
|
72
|
+
val firstRunWithStaleBundle = storedVersion == null && hasBundlePath
|
|
73
|
+
|
|
74
|
+
if (versionChanged || buildChanged || firstRunWithStaleBundle) {
|
|
75
|
+
Log.i(
|
|
76
|
+
TAG,
|
|
77
|
+
"Native version changed (${storedVersion ?: "unknown"} → ${current.versionName}, " +
|
|
78
|
+
"build ${storedBuild ?: "unknown"} → ${current.versionCode}); clearing stale OTA bundle.",
|
|
79
|
+
)
|
|
80
|
+
clearBundlePath(context)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
prefs
|
|
84
|
+
.edit()
|
|
85
|
+
.putString(KEY_NATIVE_VERSION, current.versionName)
|
|
86
|
+
.putLong(KEY_NATIVE_BUILD, current.versionCode)
|
|
87
|
+
.apply()
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fun getPendingApkPath(context: Context): String? {
|
|
91
|
+
val path =
|
|
92
|
+
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
93
|
+
.getString(KEY_PENDING_APK_PATH, null)
|
|
94
|
+
?: return null
|
|
95
|
+
|
|
96
|
+
val file = File(normalizePath(path))
|
|
97
|
+
if (!file.exists() || file.length() < MIN_APK_BYTES) {
|
|
98
|
+
clearPendingApkPath(context)
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return file.absolutePath
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
fun setPendingApkPath(context: Context, path: String): Boolean {
|
|
106
|
+
return context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
107
|
+
.edit()
|
|
108
|
+
.putString(KEY_PENDING_APK_PATH, normalizePath(path))
|
|
109
|
+
.commit()
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
fun clearPendingApkPath(context: Context) {
|
|
113
|
+
context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
|
114
|
+
.edit()
|
|
115
|
+
.remove(KEY_PENDING_APK_PATH)
|
|
116
|
+
.commit()
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fun isValidBundle(file: File): Boolean {
|
|
120
|
+
if (!file.exists() || !file.isFile || file.length() < MIN_BUNDLE_BYTES) {
|
|
121
|
+
return false
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return try {
|
|
125
|
+
file.inputStream().use { input ->
|
|
126
|
+
val header = ByteArray(4)
|
|
127
|
+
if (input.read(header) != 4) {
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Hermes bytecode (hermesc output)
|
|
132
|
+
if (isHermesBytecode(header)) {
|
|
133
|
+
return true
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Metro bundle: UTF-8 JavaScript text
|
|
137
|
+
isLikelyJavaScriptBundle(header, input)
|
|
138
|
+
}
|
|
139
|
+
} catch (_: Exception) {
|
|
140
|
+
false
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
private data class NativeInfo(val versionName: String, val versionCode: Long)
|
|
145
|
+
|
|
146
|
+
private fun readInstalledNativeInfo(context: Context): NativeInfo? {
|
|
147
|
+
return try {
|
|
148
|
+
val packageInfo =
|
|
149
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
|
150
|
+
context.packageManager.getPackageInfo(
|
|
151
|
+
context.packageName,
|
|
152
|
+
PackageManager.PackageInfoFlags.of(0),
|
|
153
|
+
)
|
|
154
|
+
} else {
|
|
155
|
+
@Suppress("DEPRECATION")
|
|
156
|
+
context.packageManager.getPackageInfo(context.packageName, 0)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
val versionName = packageInfo.versionName ?: return null
|
|
160
|
+
val versionCode =
|
|
161
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
|
162
|
+
packageInfo.longVersionCode
|
|
163
|
+
} else {
|
|
164
|
+
@Suppress("DEPRECATION")
|
|
165
|
+
packageInfo.versionCode.toLong()
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
NativeInfo(versionName, versionCode)
|
|
169
|
+
} catch (e: Exception) {
|
|
170
|
+
Log.w(TAG, "Failed to read package version for OTA clear", e)
|
|
171
|
+
null
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
private fun normalizePath(path: String): String =
|
|
176
|
+
path.removePrefix("file://")
|
|
177
|
+
|
|
178
|
+
private fun isHermesBytecode(header: ByteArray): Boolean =
|
|
179
|
+
header[0] == 0xC6.toByte() &&
|
|
180
|
+
header[1] == 0x1F.toByte() &&
|
|
181
|
+
header[2] == 0xBC.toByte() &&
|
|
182
|
+
header[3] == 0x03.toByte()
|
|
183
|
+
|
|
184
|
+
private fun isLikelyJavaScriptBundle(header: ByteArray, input: java.io.InputStream): Boolean {
|
|
185
|
+
val preview = ByteArray(64)
|
|
186
|
+
System.arraycopy(header, 0, preview, 0, 4)
|
|
187
|
+
input.read(preview, 4, 60)
|
|
188
|
+
|
|
189
|
+
val text = String(preview, Charsets.UTF_8)
|
|
190
|
+
return text.contains("__d(") ||
|
|
191
|
+
text.contains("var ") ||
|
|
192
|
+
text.startsWith("(") ||
|
|
193
|
+
text.startsWith("!") ||
|
|
194
|
+
text.startsWith(";")
|
|
195
|
+
}
|
|
196
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
package com.otaupdater
|
|
2
|
+
|
|
3
|
+
import java.io.File
|
|
4
|
+
import java.io.FileInputStream
|
|
5
|
+
import java.io.FileOutputStream
|
|
6
|
+
import java.util.zip.ZipInputStream
|
|
7
|
+
|
|
8
|
+
object OTAZipExtractHelper {
|
|
9
|
+
fun extract(zipPath: String, destDirPath: String) {
|
|
10
|
+
val zipFile = File(normalizePath(zipPath))
|
|
11
|
+
val destDir = File(normalizePath(destDirPath))
|
|
12
|
+
|
|
13
|
+
if (!zipFile.isFile) {
|
|
14
|
+
throw IllegalArgumentException("Zip file not found: ${zipFile.absolutePath}")
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (destDir.exists()) {
|
|
18
|
+
deleteRecursive(destDir)
|
|
19
|
+
}
|
|
20
|
+
destDir.mkdirs()
|
|
21
|
+
|
|
22
|
+
ZipInputStream(FileInputStream(zipFile)).use { zipInput ->
|
|
23
|
+
var entry = zipInput.nextEntry
|
|
24
|
+
while (entry != null) {
|
|
25
|
+
val outFile = safeOutputFile(destDir, entry.name)
|
|
26
|
+
|
|
27
|
+
if (entry.isDirectory) {
|
|
28
|
+
outFile.mkdirs()
|
|
29
|
+
} else {
|
|
30
|
+
outFile.parentFile?.mkdirs()
|
|
31
|
+
FileOutputStream(outFile).use { output ->
|
|
32
|
+
zipInput.copyTo(output)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
zipInput.closeEntry()
|
|
37
|
+
entry = zipInput.nextEntry
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private fun safeOutputFile(destDir: File, entryName: String): File {
|
|
43
|
+
val outFile = File(destDir, entryName)
|
|
44
|
+
val destPath = destDir.canonicalPath
|
|
45
|
+
val outPath = outFile.canonicalPath
|
|
46
|
+
if (outPath != destPath && !outPath.startsWith("$destPath${File.separator}")) {
|
|
47
|
+
throw SecurityException("Zip entry escapes target directory: $entryName")
|
|
48
|
+
}
|
|
49
|
+
return outFile
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private fun deleteRecursive(path: File) {
|
|
53
|
+
if (path.isDirectory) {
|
|
54
|
+
path.listFiles()?.forEach { child ->
|
|
55
|
+
deleteRecursive(child)
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
path.delete()
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun normalizePath(path: String): String = path.removePrefix("file://")
|
|
62
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
package com.otaupdater
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import com.facebook.react.ReactHost
|
|
5
|
+
import com.facebook.react.ReactPackage
|
|
6
|
+
import com.facebook.react.bridge.JSBundleLoader
|
|
7
|
+
import com.facebook.react.common.annotations.UnstableReactNativeAPI
|
|
8
|
+
import com.facebook.react.defaults.DefaultComponentsRegistry
|
|
9
|
+
import com.facebook.react.defaults.DefaultReactHostDelegate
|
|
10
|
+
import com.facebook.react.defaults.DefaultTurboModuleManagerDelegate
|
|
11
|
+
import com.facebook.react.fabric.ComponentFactory
|
|
12
|
+
import com.facebook.react.runtime.ReactHostImpl
|
|
13
|
+
import com.facebook.react.runtime.hermes.HermesInstance
|
|
14
|
+
import java.io.File
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Creates a fresh [ReactHost] on every cold start. Unlike [DefaultReactHost.getDefaultReactHost],
|
|
18
|
+
* this does not cache a process-wide singleton, so OTA restarts can load a new bundle path.
|
|
19
|
+
*/
|
|
20
|
+
object OTAReactHostFactory {
|
|
21
|
+
@OptIn(UnstableReactNativeAPI::class)
|
|
22
|
+
@JvmStatic
|
|
23
|
+
fun create(
|
|
24
|
+
context: Context,
|
|
25
|
+
packageList: List<ReactPackage>,
|
|
26
|
+
jsMainModulePath: String = "index",
|
|
27
|
+
jsBundleAssetPath: String = "index.android.bundle",
|
|
28
|
+
jsBundleFilePath: String? = null,
|
|
29
|
+
useDevSupport: Boolean = false,
|
|
30
|
+
): ReactHost {
|
|
31
|
+
val bundleLoader =
|
|
32
|
+
if (jsBundleFilePath != null) {
|
|
33
|
+
if (jsBundleFilePath.startsWith("assets://")) {
|
|
34
|
+
JSBundleLoader.createAssetLoader(context, jsBundleFilePath, true)
|
|
35
|
+
} else {
|
|
36
|
+
createFileBundleLoader(jsBundleFilePath)
|
|
37
|
+
}
|
|
38
|
+
} else {
|
|
39
|
+
JSBundleLoader.createAssetLoader(context, "assets://$jsBundleAssetPath", true)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
val turboModuleDelegateBuilder = DefaultTurboModuleManagerDelegate.Builder()
|
|
43
|
+
val reactHostDelegate =
|
|
44
|
+
DefaultReactHostDelegate(
|
|
45
|
+
jsMainModulePath = jsMainModulePath,
|
|
46
|
+
jsBundleLoader = bundleLoader,
|
|
47
|
+
reactPackages = packageList,
|
|
48
|
+
jsRuntimeFactory = HermesInstance(),
|
|
49
|
+
bindingsInstaller = null,
|
|
50
|
+
turboModuleManagerDelegateBuilder = turboModuleDelegateBuilder,
|
|
51
|
+
exceptionHandler = { throw it },
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
val componentFactory = ComponentFactory()
|
|
55
|
+
DefaultComponentsRegistry.register(componentFactory)
|
|
56
|
+
|
|
57
|
+
return ReactHostImpl(
|
|
58
|
+
context,
|
|
59
|
+
reactHostDelegate,
|
|
60
|
+
componentFactory,
|
|
61
|
+
true,
|
|
62
|
+
useDevSupport,
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Load JS from disk with sibling drawable assets (OTA zip extract folder). */
|
|
67
|
+
private fun createFileBundleLoader(jsBundleFilePath: String): JSBundleLoader {
|
|
68
|
+
return try {
|
|
69
|
+
val bundleFile = File(jsBundleFilePath)
|
|
70
|
+
val assetUrl =
|
|
71
|
+
"file://${bundleFile.parentFile?.absolutePath?.trimEnd('/')}/"
|
|
72
|
+
val method =
|
|
73
|
+
JSBundleLoader::class.java.getMethod(
|
|
74
|
+
"createFileLoader",
|
|
75
|
+
String::class.java,
|
|
76
|
+
String::class.java,
|
|
77
|
+
Boolean::class.javaPrimitiveType,
|
|
78
|
+
)
|
|
79
|
+
method.invoke(null, jsBundleFilePath, assetUrl, true) as JSBundleLoader
|
|
80
|
+
} catch (_: Exception) {
|
|
81
|
+
JSBundleLoader.createFileLoader(jsBundleFilePath)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
#import "OTAUpdaterNative.h"
|
|
2
|
+
#import <React/RCTLog.h>
|
|
3
|
+
#import <React/RCTReloadCommand.h>
|
|
4
|
+
#import <UIKit/UIKit.h>
|
|
5
|
+
|
|
6
|
+
static NSString *const kBundlePathKey = @"ota_updater_bundle_path";
|
|
7
|
+
static NSString *const kNativeVersionKey = @"ota_updater_native_version";
|
|
8
|
+
static NSString *const kNativeBuildKey = @"ota_updater_native_build";
|
|
9
|
+
|
|
10
|
+
@implementation OTAUpdaterNative
|
|
11
|
+
|
|
12
|
+
RCT_EXPORT_MODULE();
|
|
13
|
+
|
|
14
|
+
+ (void)clearStaleBundleAfterNativeUpgrade {
|
|
15
|
+
NSDictionary *info = [[NSBundle mainBundle] infoDictionary];
|
|
16
|
+
NSString *currentVersion = info[@"CFBundleShortVersionString"];
|
|
17
|
+
NSString *currentBuild = info[@"CFBundleVersion"];
|
|
18
|
+
if (currentVersion == nil) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
|
|
23
|
+
NSString *storedVersion = [defaults stringForKey:kNativeVersionKey];
|
|
24
|
+
NSString *storedBuild = [defaults stringForKey:kNativeBuildKey];
|
|
25
|
+
BOOL hasBundlePath = [defaults objectForKey:kBundlePathKey] != nil;
|
|
26
|
+
|
|
27
|
+
BOOL versionChanged = storedVersion != nil && ![storedVersion isEqualToString:currentVersion];
|
|
28
|
+
BOOL buildChanged =
|
|
29
|
+
currentBuild != nil && storedBuild != nil && ![storedBuild isEqualToString:currentBuild];
|
|
30
|
+
BOOL firstRunWithStaleBundle = storedVersion == nil && hasBundlePath;
|
|
31
|
+
|
|
32
|
+
if (versionChanged || buildChanged || firstRunWithStaleBundle) {
|
|
33
|
+
RCTLogInfo(@"[OTA] Native version changed; clearing stale OTA bundle.");
|
|
34
|
+
[defaults removeObjectForKey:kBundlePathKey];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
[defaults setObject:currentVersion forKey:kNativeVersionKey];
|
|
38
|
+
if (currentBuild != nil) {
|
|
39
|
+
[defaults setObject:currentBuild forKey:kNativeBuildKey];
|
|
40
|
+
}
|
|
41
|
+
[defaults synchronize];
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
+ (NSString *)otaBundlePath {
|
|
45
|
+
[OTAUpdaterNative clearStaleBundleAfterNativeUpgrade];
|
|
46
|
+
|
|
47
|
+
NSString *path = [[NSUserDefaults standardUserDefaults] stringForKey:kBundlePathKey];
|
|
48
|
+
if (path != nil && [[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
|
49
|
+
return path;
|
|
50
|
+
}
|
|
51
|
+
return nil;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
RCT_EXPORT_METHOD(setBundlePath:(NSString *)path
|
|
55
|
+
resolver:(RCTPromiseResolveBlock)resolve
|
|
56
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
57
|
+
{
|
|
58
|
+
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
|
59
|
+
reject(@"ENOENT", @"Bundle file not found", nil);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
[[NSUserDefaults standardUserDefaults] setObject:path forKey:kBundlePathKey];
|
|
64
|
+
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
65
|
+
resolve(path);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
RCT_EXPORT_METHOD(clearBundlePath:(RCTPromiseResolveBlock)resolve
|
|
69
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
70
|
+
{
|
|
71
|
+
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kBundlePathKey];
|
|
72
|
+
[[NSUserDefaults standardUserDefaults] synchronize];
|
|
73
|
+
resolve(@YES);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
RCT_EXPORT_METHOD(restartApp:(RCTPromiseResolveBlock)resolve
|
|
77
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
78
|
+
{
|
|
79
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
80
|
+
#if DEBUG
|
|
81
|
+
NSString *otaPath = [OTAUpdaterNative otaBundlePath];
|
|
82
|
+
if (otaPath != nil) {
|
|
83
|
+
RCTTriggerReloadCommandListeners(@"OTA update applied");
|
|
84
|
+
resolve(@"reloaded");
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
#endif
|
|
88
|
+
|
|
89
|
+
UIApplication *application = [UIApplication sharedApplication];
|
|
90
|
+
__block UIBackgroundTaskIdentifier taskId = UIBackgroundTaskInvalid;
|
|
91
|
+
|
|
92
|
+
taskId = [application beginBackgroundTaskWithExpirationHandler:^{
|
|
93
|
+
[application endBackgroundTask:taskId];
|
|
94
|
+
taskId = UIBackgroundTaskInvalid;
|
|
95
|
+
}];
|
|
96
|
+
|
|
97
|
+
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
|
|
98
|
+
exit(0);
|
|
99
|
+
resolve(@"restarted");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
RCT_EXPORT_METHOD(getBundlePath:(RCTPromiseResolveBlock)resolve
|
|
105
|
+
rejecter:(RCTPromiseRejectBlock)reject)
|
|
106
|
+
{
|
|
107
|
+
resolve([OTAUpdaterNative otaBundlePath] ?: [NSNull null]);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@end
|
package/lib/api.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { checkForUpdate, downloadBundle, getBundleFilePath, verifyBundleHash, } from './sync';
|
package/lib/api.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.verifyBundleHash = exports.getBundleFilePath = exports.downloadBundle = exports.checkForUpdate = void 0;
|
|
4
|
+
var sync_1 = require("./sync");
|
|
5
|
+
Object.defineProperty(exports, "checkForUpdate", { enumerable: true, get: function () { return sync_1.checkForUpdate; } });
|
|
6
|
+
Object.defineProperty(exports, "downloadBundle", { enumerable: true, get: function () { return sync_1.downloadBundle; } });
|
|
7
|
+
Object.defineProperty(exports, "getBundleFilePath", { enumerable: true, get: function () { return sync_1.getBundleFilePath; } });
|
|
8
|
+
Object.defineProperty(exports, "verifyBundleHash", { enumerable: true, get: function () { return sync_1.verifyBundleHash; } });
|
package/lib/config.d.ts
ADDED
package/lib/config.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.configure = configure;
|
|
4
|
+
exports.getConfig = getConfig;
|
|
5
|
+
let config = null;
|
|
6
|
+
function configure(options) {
|
|
7
|
+
config = options;
|
|
8
|
+
}
|
|
9
|
+
function getConfig() {
|
|
10
|
+
return config;
|
|
11
|
+
}
|
package/lib/debug.d.ts
ADDED