diff --git a/.gitignore b/.gitignore
index c51d7b6db..4c0623576 100644
--- a/.gitignore
+++ b/.gitignore
@@ -150,9 +150,6 @@ proguard/
# Android Studio captures folder
captures/
-# Remove after this framework is published on NPM
-code-push-plugin-testing-framework/node_modules
-
# Windows
windows/.vs/
windows/obj/
@@ -192,4 +189,4 @@ Examples/testapp_rn
# Android debug build files (conflict ignoring #Visual Studio files)
!android/app/src/debug/
-.temp/
\ No newline at end of file
+.temp/
diff --git a/.npmignore b/.npmignore
index d385ceef2..754f0a0a5 100644
--- a/.npmignore
+++ b/.npmignore
@@ -34,10 +34,8 @@ Recipes/
bin/
test/
-# Remove after this framework is published on NPM
-code-push-plugin-testing-framework/
-
# Android build artifacts and Android Studio bits
+android/build
android/app/build
android/local.properties
android/.gradle
diff --git a/AlertAdapter.js b/AlertAdapter.js
index 124375891..260491e24 100644
--- a/AlertAdapter.js
+++ b/AlertAdapter.js
@@ -2,7 +2,22 @@ import React, { Platform } from "react-native";
let { Alert } = React;
if (Platform.OS === "android") {
- const { NativeModules: { CodePushDialog } } = React;
+ function resolveNativeModule(name) {
+ const ReactNative = require("react-native");
+ try {
+ const turboModule =
+ ReactNative.TurboModuleRegistry && ReactNative.TurboModuleRegistry.get
+ ? ReactNative.TurboModuleRegistry.get(name)
+ : null;
+ if (turboModule) return turboModule;
+ } catch (_e) {
+ // Ignore and fall back to legacy NativeModules.
+ }
+
+ return ReactNative.NativeModules ? ReactNative.NativeModules[name] : null;
+ }
+
+ const CodePushDialog = resolveNativeModule("CodePushDialog");
Alert = {
alert(title, message, buttons) {
@@ -13,6 +28,10 @@ if (Platform.OS === "android") {
const button1Text = buttons[0] ? buttons[0].text : null,
button2Text = buttons[1] ? buttons[1].text : null;
+ if (!CodePushDialog) {
+ throw "CodePushDialog native module is not installed.";
+ }
+
CodePushDialog.showDialog(
title, message, button1Text, button2Text,
(buttonId) => { buttons[buttonId].onPress && buttons[buttonId].onPress(); },
@@ -21,4 +40,4 @@ if (Platform.OS === "android") {
};
}
-module.exports = { Alert };
\ No newline at end of file
+module.exports = { Alert };
diff --git a/CodePush.js b/CodePush.js
index 2d1d9deda..c811bb07a 100644
--- a/CodePush.js
+++ b/CodePush.js
@@ -5,7 +5,22 @@ import { AppState, Platform } from "react-native";
import log from "./logging";
import hoistStatics from 'hoist-non-react-statics';
-let NativeCodePush = require("react-native").NativeModules.CodePush;
+function resolveNativeModule(name) {
+ const ReactNative = require("react-native");
+ try {
+ const turboModule =
+ ReactNative.TurboModuleRegistry && ReactNative.TurboModuleRegistry.get
+ ? ReactNative.TurboModuleRegistry.get(name)
+ : null;
+ if (turboModule) return turboModule;
+ } catch (_e) {
+ // Ignore and fall back to legacy NativeModules.
+ }
+
+ return ReactNative.NativeModules ? ReactNative.NativeModules[name] : null;
+}
+
+let NativeCodePush = resolveNativeModule("CodePush");
const PackageMixins = require("./package-mixins")(NativeCodePush);
async function checkForUpdate(deploymentKey = null, handleBinaryVersionMismatchCallback = null) {
diff --git a/CodePush.podspec b/CodePush.podspec
index 6d354a1ea..3d896818a 100644
--- a/CodePush.podspec
+++ b/CodePush.podspec
@@ -10,8 +10,8 @@ Pod::Spec.new do |s|
s.license = package['license']
s.homepage = package['homepage']
s.source = { :git => 'https://github.com/srcpush/react-native-code-push.git', :tag => "v#{s.version}"}
- s.ios.deployment_target = '15.5'
- s.tvos.deployment_target = '15.5'
+ s.ios.deployment_target = '11.0'
+ s.tvos.deployment_target = '11.0'
s.preserve_paths = '*.js'
s.library = 'z'
s.source_files = 'ios/CodePush/*.{h,m}'
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 133dd3e36..38f92c399 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -1,48 +1,98 @@
-apply plugin: "com.android.library"
-
-def isNewArchitectureEnabled() {
- // To opt-in for the New Architecture, you can either:
- // - Set `newArchEnabled` to true inside the `gradle.properties` file
- // - Invoke gradle with `-newArchEnabled=true`
- // - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
- return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
-}
+import groovy.json.JsonSlurper
-def IS_NEW_ARCHITECTURE_ENABLED = isNewArchitectureEnabled()
+apply plugin: "com.android.library"
-if (IS_NEW_ARCHITECTURE_ENABLED) {
- apply plugin: "com.facebook.react"
+def safeExtGet(prop, fallback) {
+ return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
def DEFAULT_COMPILE_SDK_VERSION = 26
-def DEFAULT_BUILD_TOOLS_VERSION = "26.0.3"
def DEFAULT_TARGET_SDK_VERSION = 26
def DEFAULT_MIN_SDK_VERSION = 16
+def findReactNativePackageJson() {
+ File currentDir = projectDir
+
+ while (currentDir != null) {
+ File packageJson = new File(currentDir, "node_modules/react-native/package.json")
+ if (packageJson.exists()) {
+ return packageJson
+ }
+
+ currentDir = currentDir.parentFile
+ }
+
+ return null
+}
+
+def getReactNativeVersion() {
+ File packageJson = findReactNativePackageJson()
+ if (packageJson == null) {
+ return null
+ }
+
+ def version = new JsonSlurper().parseText(packageJson.text).version
+ return version.tokenize("-")[0]
+}
+
+def getReactNativeMinorVersion() {
+ def reactNativeVersion = getReactNativeVersion()
+ if (reactNativeVersion == null) {
+ return null
+ }
+
+ def versionParts = reactNativeVersion.tokenize(".")
+ if (versionParts.size() < 2) {
+ return null
+ }
+
+ return versionParts[1].toInteger()
+}
+
+def reactNativeVersion = getReactNativeVersion()
+def reactNativeMinorVersion = getReactNativeMinorVersion()
+def reactNativeDependency = reactNativeMinorVersion != null && reactNativeMinorVersion < 71
+ ? "com.facebook.react:react-native:${reactNativeVersion ?: '+'}"
+ : "com.facebook.react:react-android:${reactNativeVersion ?: '+'}"
+
android {
- namespace "com.microsoft.codepush.react"
+ if (project.android.hasProperty("namespace")) {
+ namespace "com.microsoft.codepush.react"
+ }
- compileSdkVersion rootProject.hasProperty('compileSdkVersion') ? rootProject.compileSdkVersion : DEFAULT_COMPILE_SDK_VERSION
- buildToolsVersion rootProject.hasProperty('buildToolsVersion') ? rootProject.buildToolsVersion : DEFAULT_BUILD_TOOLS_VERSION
+ compileSdkVersion safeExtGet("compileSdkVersion", DEFAULT_COMPILE_SDK_VERSION)
defaultConfig {
- minSdkVersion rootProject.hasProperty('minSdkVersion') ? rootProject.minSdkVersion : DEFAULT_MIN_SDK_VERSION
- targetSdkVersion rootProject.hasProperty('targetSdkVersion') ? rootProject.targetSdkVersion : DEFAULT_TARGET_SDK_VERSION
+ minSdkVersion safeExtGet("minSdkVersion", DEFAULT_MIN_SDK_VERSION)
+ targetSdkVersion safeExtGet("targetSdkVersion", DEFAULT_TARGET_SDK_VERSION)
versionCode 1
versionName "1.0"
- buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", IS_NEW_ARCHITECTURE_ENABLED.toString()
+ consumerProguardFiles "../proguard-rules.pro"
+ }
+
+ sourceSets {
+ main {
+ java.srcDirs = ["../src/main/java"]
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
abortOnError false
}
+}
- defaultConfig {
- consumerProguardFiles 'proguard-rules.pro'
- }
+repositories {
+ google()
+ mavenCentral()
+ mavenLocal()
}
dependencies {
- implementation "com.facebook.react:react-native:+"
- implementation 'com.nimbusds:nimbus-jose-jwt:9.37.3'
+ implementation(reactNativeDependency)
+ implementation "com.nimbusds:nimbus-jose-jwt:9.37.3"
}
diff --git a/android/app/src/debug/AndroidManifest.xml b/android/app/src/debug/AndroidManifest.xml
index df32a1faf..fbb2ef838 100644
--- a/android/app/src/debug/AndroidManifest.xml
+++ b/android/app/src/debug/AndroidManifest.xml
@@ -1,9 +1,3 @@
-
-
-
-
-
-
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index b07e42801..96ba5b66f 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -1,5 +1,2 @@
-
-
-
-
-
+
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/ReactHostHolder.java b/android/app/src/main/java/com/microsoft/codepush/react/ReactHostHolder.java
deleted file mode 100644
index a5d54fdfc..000000000
--- a/android/app/src/main/java/com/microsoft/codepush/react/ReactHostHolder.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.microsoft.codepush.react;
-
-import com.facebook.react.ReactHost;
-import com.facebook.react.runtime.ReactHostDelegate;
-
-/**
- * Provides access to a {@link ReactHostDelegate}
- */
-public interface ReactHostHolder {
- ReactHost getReactHost();
-}
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index 31a524838..6bcd77cb9 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,24 +1,106 @@
-// Top-level build file where you can add configuration options common to all sub-projects/modules.
+import groovy.json.JsonSlurper
buildscript {
+ ext {
+ kotlinVersion = "1.9.24"
+ }
repositories {
google()
mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:1.3.0'
+ classpath("com.android.tools.build:gradle:8.2.1")
+ classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
+ }
+}
+
+apply plugin: "com.android.library"
+
+def safeExtGet(prop, fallback) {
+ return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
+}
+
+def DEFAULT_COMPILE_SDK_VERSION = 26
+def DEFAULT_TARGET_SDK_VERSION = 26
+def DEFAULT_MIN_SDK_VERSION = 16
+
+def findReactNativePackageJson() {
+ File currentDir = projectDir
+
+ while (currentDir != null) {
+ File packageJson = new File(currentDir, "node_modules/react-native/package.json")
+ if (packageJson.exists()) {
+ return packageJson
+ }
- // NOTE: Do not place your application dependencies here; they belong
- // in the individual module build.gradle files
+ currentDir = currentDir.parentFile
}
+
+ return null
+}
+
+def getReactNativeVersion() {
+ File packageJson = findReactNativePackageJson()
+ if (packageJson == null) {
+ return null
+ }
+
+ def version = new JsonSlurper().parseText(packageJson.text).version
+ return version.tokenize("-")[0]
}
-allprojects {
- android {
+def getReactNativeMinorVersion() {
+ def reactNativeVersion = getReactNativeVersion()
+ if (reactNativeVersion == null) {
+ return null
+ }
+
+ def versionParts = reactNativeVersion.tokenize(".")
+ if (versionParts.size() < 2) {
+ return null
+ }
+
+ return versionParts[1].toInteger()
+}
+
+def reactNativeVersion = getReactNativeVersion()
+def reactNativeMinorVersion = getReactNativeMinorVersion()
+def reactNativeDependency = reactNativeMinorVersion != null && reactNativeMinorVersion < 71
+ ? "com.facebook.react:react-native:${reactNativeVersion ?: '+'}"
+ : "com.facebook.react:react-android:${reactNativeVersion ?: '+'}"
+
+android {
+ if (project.android.hasProperty("namespace")) {
namespace "com.microsoft.codepush.react"
}
- repositories {
- mavenLocal()
- mavenCentral()
+
+ compileSdkVersion safeExtGet("compileSdkVersion", DEFAULT_COMPILE_SDK_VERSION)
+
+ defaultConfig {
+ minSdkVersion safeExtGet("minSdkVersion", DEFAULT_MIN_SDK_VERSION)
+ targetSdkVersion safeExtGet("targetSdkVersion", DEFAULT_TARGET_SDK_VERSION)
+ versionCode 1
+ versionName "1.0"
+ consumerProguardFiles "proguard-rules.pro"
}
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ lintOptions {
+ abortOnError false
+ }
+}
+
+repositories {
+ google()
+ mavenCentral()
+ mavenLocal()
+}
+
+dependencies {
+ implementation(reactNativeDependency)
+ implementation "com.nimbusds:nimbus-jose-jwt:9.37.3"
}
diff --git a/android/gradle.properties b/android/gradle.properties
index 1fd964e90..f54c3e7fd 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -10,11 +10,11 @@
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
-# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+org.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8
+android.useAndroidX=true
+android.enableJetifier=true
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
-
-android.useDeprecatedNdk=true
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index b9fbfaba0..45181329e 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
diff --git a/android/app/proguard-rules.pro b/android/proguard-rules.pro
similarity index 100%
rename from android/app/proguard-rules.pro
rename to android/proguard-rules.pro
diff --git a/android/settings.gradle b/android/settings.gradle
deleted file mode 100644
index 9d495b34f..000000000
--- a/android/settings.gradle
+++ /dev/null
@@ -1 +0,0 @@
-include ':app'
\ No newline at end of file
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
new file mode 100644
index 000000000..b07e42801
--- /dev/null
+++ b/android/src/main/AndroidManifest.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java b/android/src/main/java/com/microsoft/codepush/react/CodePush.java
similarity index 96%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePush.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePush.java
index df6d6430f..0c614b3e4 100644
--- a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java
+++ b/android/src/main/java/com/microsoft/codepush/react/CodePush.java
@@ -5,7 +5,6 @@
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import com.facebook.react.ReactHost;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
@@ -60,6 +59,7 @@ public static CodePush getInstance(String deploymentKey, Context context, boolea
private static ReactInstanceHolder mReactInstanceHolder;
private static ReactHostHolder mReactHostHolder;
+ private static Object mReactHost;
public CodePush(String deploymentKey, Context context) {
this(deploymentKey, context, false);
@@ -69,7 +69,7 @@ public static String getServiceUrl() {
return mServerUrl;
}
- private CodePush(String deploymentKey, Context context, boolean isDebugMode) {
+ public CodePush(String deploymentKey, Context context, boolean isDebugMode) {
mContext = context.getApplicationContext();
mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath());
@@ -406,6 +406,10 @@ public static void setReactHost(ReactHostHolder reactHostHolder) {
mReactHostHolder = reactHostHolder;
}
+ public static void setReactHost(Object reactHost) {
+ mReactHost = reactHost;
+ }
+
static ReactInstanceManager getReactInstanceManager() {
if (mReactInstanceHolder == null) {
return null;
@@ -413,7 +417,11 @@ static ReactInstanceManager getReactInstanceManager() {
return mReactInstanceHolder.getReactInstanceManager();
}
- static ReactHost getReactHost() {
+ static Object getReactHost() {
+ if (mReactHost != null) {
+ return mReactHost;
+ }
+
if (mReactHostHolder == null) {
return null;
}
@@ -423,13 +431,10 @@ static ReactHost getReactHost() {
@Override
public List createNativeModules(ReactApplicationContext reactApplicationContext) {
- CodePushNativeModule codePushModule = new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager);
- CodePushDialog dialogModule = new CodePushDialog(reactApplicationContext);
-
- List nativeModules = new ArrayList<>();
- nativeModules.add(codePushModule);
- nativeModules.add(dialogModule);
- return nativeModules;
+ List modules = new ArrayList<>();
+ modules.add(new CodePushNativeModule(reactApplicationContext, this, mUpdateManager, mTelemetryManager, mSettingsManager));
+ modules.add(new CodePushDialog(reactApplicationContext));
+ return modules;
}
// Deprecated in RN v0.47.
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java b/android/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushBuilder.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushConstants.java b/android/src/main/java/com/microsoft/codepush/react/CodePushConstants.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushConstants.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushConstants.java
diff --git a/android/src/main/java/com/microsoft/codepush/react/CodePushDialog.java b/android/src/main/java/com/microsoft/codepush/react/CodePushDialog.java
new file mode 100644
index 000000000..973306e0f
--- /dev/null
+++ b/android/src/main/java/com/microsoft/codepush/react/CodePushDialog.java
@@ -0,0 +1,50 @@
+package com.microsoft.codepush.react;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.Callback;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactMethod;
+
+public class CodePushDialog extends BaseJavaModule {
+ public static final String NAME = "CodePushDialog";
+
+ private final CodePushDialogImpl impl;
+
+ public CodePushDialog(ReactApplicationContext reactContext) {
+ super(reactContext);
+ impl = new CodePushDialogImpl(reactContext);
+ }
+
+ @ReactMethod
+ public void showDialog(
+ final String title,
+ final String message,
+ final String button1Text,
+ final String button2Text,
+ final Callback successCallback,
+ Callback errorCallback
+ ) {
+ try {
+ impl.showDialog(title, message, button1Text, button2Text, successCallback, errorCallback);
+ } catch (Throwable e) {
+ if (errorCallback != null) {
+ errorCallback.invoke(e.getMessage());
+ }
+ }
+ }
+
+ @ReactMethod
+ public void addListener(String eventName) {
+ // no-op
+ }
+
+ @ReactMethod
+ public void removeListeners(double count) {
+ // no-op
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+}
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java b/android/src/main/java/com/microsoft/codepush/react/CodePushDialogImpl.java
similarity index 59%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushDialogImpl.java
index 66236eafa..e6c01ed61 100644
--- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushDialog.java
+++ b/android/src/main/java/com/microsoft/codepush/react/CodePushDialogImpl.java
@@ -4,43 +4,43 @@
import android.app.AlertDialog;
import android.content.DialogInterface;
-import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactMethod;
-public class CodePushDialog extends BaseJavaModule {
+final class CodePushDialogImpl {
+ private final ReactApplicationContext reactContext;
- public CodePushDialog(ReactApplicationContext reactContext) {
- super(reactContext);
+ CodePushDialogImpl(ReactApplicationContext reactContext) {
+ this.reactContext = reactContext;
}
- @ReactMethod
- public void showDialog(final String title, final String message, final String button1Text,
- final String button2Text, final Callback successCallback, Callback errorCallback) {
- Activity currentActivity = getReactApplicationContext().getCurrentActivity();
+ void showDialog(
+ final String title,
+ final String message,
+ final String button1Text,
+ final String button2Text,
+ final Callback successCallback,
+ final Callback errorCallback
+ ) {
+ Activity currentActivity = reactContext.getCurrentActivity();
if (currentActivity == null || currentActivity.isFinishing()) {
- // If getCurrentActivity is null, it could be because the app is backgrounded,
- // so we show the dialog when the app resumes)
- getReactApplicationContext().addLifecycleEventListener(new LifecycleEventListener() {
+ reactContext.addLifecycleEventListener(new LifecycleEventListener() {
@Override
public void onHostResume() {
- Activity currentActivity = getReactApplicationContext().getCurrentActivity();
- if (currentActivity != null) {
- getReactApplicationContext().removeLifecycleEventListener(this);
- showDialogInternal(title, message, button1Text, button2Text, successCallback, currentActivity);
+ Activity resumedActivity = reactContext.getCurrentActivity();
+ if (resumedActivity != null && !resumedActivity.isFinishing()) {
+ reactContext.removeLifecycleEventListener(this);
+ showDialogInternal(title, message, button1Text, button2Text, successCallback, resumedActivity);
}
}
@Override
public void onHostPause() {
-
}
@Override
public void onHostDestroy() {
-
}
});
} else {
@@ -48,10 +48,15 @@ public void onHostDestroy() {
}
}
- private void showDialogInternal(String title, String message, String button1Text,
- String button2Text, final Callback successCallback, Activity currentActivity) {
+ private void showDialogInternal(
+ String title,
+ String message,
+ String button1Text,
+ String button2Text,
+ final Callback successCallback,
+ Activity currentActivity
+ ) {
AlertDialog.Builder builder = new AlertDialog.Builder(currentActivity);
-
builder.setCancelable(false);
DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
@@ -61,10 +66,10 @@ public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
- successCallback.invoke(0);
+ if (successCallback != null) successCallback.invoke(0);
break;
case DialogInterface.BUTTON_NEGATIVE:
- successCallback.invoke(1);
+ if (successCallback != null) successCallback.invoke(1);
break;
default:
throw new CodePushUnknownException("Unknown button ID pressed.");
@@ -94,9 +99,4 @@ public void onClick(DialogInterface dialog, int which) {
AlertDialog dialog = builder.create();
dialog.show();
}
-
- @Override
- public String getName() {
- return "CodePushDialog";
- }
}
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java b/android/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushInstallMode.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java b/android/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushInvalidPublicKeyException.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java b/android/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushInvalidUpdateException.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushMalformedDataException.java b/android/src/main/java/com/microsoft/codepush/react/CodePushMalformedDataException.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushMalformedDataException.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushMalformedDataException.java
diff --git a/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java b/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java
new file mode 100644
index 000000000..3725cc98c
--- /dev/null
+++ b/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java
@@ -0,0 +1,136 @@
+package com.microsoft.codepush.react;
+
+import com.facebook.react.bridge.BaseJavaModule;
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+
+import java.util.Map;
+
+public class CodePushNativeModule extends BaseJavaModule {
+ public static final String NAME = "CodePush";
+
+ private final CodePushNativeModuleImpl impl;
+
+ public CodePushNativeModule(
+ ReactApplicationContext reactContext,
+ CodePush codePush,
+ CodePushUpdateManager codePushUpdateManager,
+ CodePushTelemetryManager codePushTelemetryManager,
+ SettingsManager settingsManager
+ ) {
+ super(reactContext);
+ impl = new CodePushNativeModuleImpl(reactContext, codePush, codePushUpdateManager, codePushTelemetryManager, settingsManager);
+ }
+
+ @Override
+ public Map getConstants() {
+ return impl.getConstants();
+ }
+
+ @Override
+ public String getName() {
+ return NAME;
+ }
+
+ @ReactMethod
+ public void allow(Promise promise) {
+ impl.allow(promise);
+ }
+
+ @ReactMethod
+ public void clearPendingRestart(Promise promise) {
+ impl.clearPendingRestart(promise);
+ }
+
+ @ReactMethod
+ public void disallow(Promise promise) {
+ impl.disallow(promise);
+ }
+
+ @ReactMethod
+ public void restartApp(boolean onlyIfUpdateIsPending, Promise promise) {
+ impl.restartApp(onlyIfUpdateIsPending, promise);
+ }
+
+ @ReactMethod
+ public void downloadUpdate(ReadableMap updatePackage, boolean notifyProgress, Promise promise) {
+ impl.downloadUpdate(updatePackage, notifyProgress, promise);
+ }
+
+ @ReactMethod
+ public void getConfiguration(Promise promise) {
+ impl.getConfiguration(promise);
+ }
+
+ @ReactMethod
+ public void getUpdateMetadata(double updateState, Promise promise) {
+ impl.getUpdateMetadata(updateState, promise);
+ }
+
+ @ReactMethod
+ public void getNewStatusReport(Promise promise) {
+ impl.getNewStatusReport(promise);
+ }
+
+ @ReactMethod
+ public void installUpdate(ReadableMap updatePackage, double installMode, double minimumBackgroundDuration, Promise promise) {
+ impl.installUpdate(updatePackage, installMode, minimumBackgroundDuration, promise);
+ }
+
+ @ReactMethod
+ public void isFailedUpdate(String packageHash, Promise promise) {
+ impl.isFailedUpdate(packageHash, promise);
+ }
+
+ @ReactMethod
+ public void getLatestRollbackInfo(Promise promise) {
+ impl.getLatestRollbackInfo(promise);
+ }
+
+ @ReactMethod
+ public void setLatestRollbackInfo(String packageHash, Promise promise) {
+ impl.setLatestRollbackInfo(packageHash, promise);
+ }
+
+ @ReactMethod
+ public void isFirstRun(String packageHash, Promise promise) {
+ impl.isFirstRun(packageHash, promise);
+ }
+
+ @ReactMethod
+ public void notifyApplicationReady(Promise promise) {
+ impl.notifyApplicationReady(promise);
+ }
+
+ @ReactMethod
+ public void recordStatusReported(ReadableMap statusReport) {
+ impl.recordStatusReported(statusReport);
+ }
+
+ @ReactMethod
+ public void saveStatusReportForRetry(ReadableMap statusReport) {
+ impl.saveStatusReportForRetry(statusReport);
+ }
+
+ @ReactMethod
+ public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
+ impl.downloadAndReplaceCurrentBundle(remoteBundleUrl);
+ }
+
+ @ReactMethod
+ public void clearUpdates() {
+ impl.clearUpdates();
+ }
+
+ @ReactMethod
+ public void addListener(String eventName) {
+ impl.addListener(eventName);
+ }
+
+ @ReactMethod
+ public void removeListeners(double count) {
+ impl.removeListeners(count);
+ }
+}
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java b/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModuleImpl.java
similarity index 60%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushNativeModuleImpl.java
index aabae6ec2..69f2de330 100644
--- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushNativeModule.java
+++ b/android/src/main/java/com/microsoft/codepush/react/CodePushNativeModuleImpl.java
@@ -5,31 +5,23 @@
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
+import android.view.Choreographer;
import android.view.View;
-import androidx.annotation.OptIn;
-
import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactHost;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.Arguments;
-import com.facebook.react.bridge.BaseJavaModule;
import com.facebook.react.bridge.JSBundleLoader;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
-import com.facebook.react.common.annotations.UnstableReactNativeAPI;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.modules.core.ReactChoreographer;
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
-import com.facebook.react.runtime.ReactHostDelegate;
-import com.facebook.react.runtime.ReactHostImpl;
-import android.view.Choreographer;
import org.json.JSONArray;
import org.json.JSONException;
@@ -45,31 +37,35 @@
import java.util.Map;
import java.util.UUID;
-@OptIn(markerClass = UnstableReactNativeAPI.class)
-public class CodePushNativeModule extends BaseJavaModule {
+final class CodePushNativeModuleImpl {
private String mBinaryContentsHash = null;
private String mClientUniqueId = null;
private LifecycleEventListener mLifecycleEventListener = null;
private int mMinimumBackgroundDuration = 0;
- private CodePush mCodePush;
- private SettingsManager mSettingsManager;
- private CodePushTelemetryManager mTelemetryManager;
- private CodePushUpdateManager mUpdateManager;
-
- private boolean _allowed = true;
- private boolean _restartInProgress = false;
- private ArrayList _restartQueue = new ArrayList<>();
-
- public CodePushNativeModule(ReactApplicationContext reactContext, CodePush codePush, CodePushUpdateManager codePushUpdateManager, CodePushTelemetryManager codePushTelemetryManager, SettingsManager settingsManager) {
- super(reactContext);
-
+ private final ReactApplicationContext reactContext;
+ private final CodePush mCodePush;
+ private final SettingsManager mSettingsManager;
+ private final CodePushTelemetryManager mTelemetryManager;
+ private final CodePushUpdateManager mUpdateManager;
+
+ private boolean _allowed = true;
+ private boolean _restartInProgress = false;
+ private final ArrayList _restartQueue = new ArrayList<>();
+
+ CodePushNativeModuleImpl(
+ ReactApplicationContext reactContext,
+ CodePush codePush,
+ CodePushUpdateManager codePushUpdateManager,
+ CodePushTelemetryManager codePushTelemetryManager,
+ SettingsManager settingsManager
+ ) {
+ this.reactContext = reactContext;
mCodePush = codePush;
mSettingsManager = settingsManager;
mTelemetryManager = codePushTelemetryManager;
mUpdateManager = codePushUpdateManager;
- // Initialize module state while we have a reference to the current context.
mBinaryContentsHash = CodePushUpdateUtils.getHashForBinaryContents(reactContext, mCodePush.isDebugMode());
SharedPreferences preferences = codePush.getContext().getSharedPreferences(CodePushConstants.CODE_PUSH_PREFERENCES, 0);
@@ -80,8 +76,7 @@ public CodePushNativeModule(ReactApplicationContext reactContext, CodePush codeP
}
}
- @Override
- public Map getConstants() {
+ Map getConstants() {
final Map constants = new HashMap<>();
constants.put("codePushInstallModeImmediate", CodePushInstallMode.IMMEDIATE.getValue());
@@ -96,16 +91,9 @@ public Map getConstants() {
return constants;
}
- @Override
- public String getName() {
- return "CodePush";
- }
-
private void loadBundleLegacy() {
- final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
+ final Activity currentActivity = reactContext.getCurrentActivity();
if (currentActivity == null) {
- // The currentActivity can be null if it is backgrounded / destroyed, so we simply
- // no-op to prevent any null pointer exceptions.
return;
}
mCodePush.invalidateCurrentInstance();
@@ -118,13 +106,11 @@ public void run() {
});
}
- // Use reflection to find and set the appropriate fields on ReactInstanceManager. See #556 for a proposal for a less brittle way
- // to approach this.
private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBundleFile) throws IllegalAccessException {
try {
JSBundleLoader latestJSBundleLoader;
if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
- latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
+ latestJSBundleLoader = JSBundleLoader.createAssetLoader(reactContext, latestJSBundleFile, false);
} else {
latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
}
@@ -138,131 +124,50 @@ private void setJSBundle(ReactInstanceManager instanceManager, String latestJSBu
}
}
- // Use reflection to find and set the appropriate fields on ReactHostDelegate. See #556 for a proposal for a less brittle way
- // to approach this.
- private void setJSBundle(ReactHostDelegate reactHostDelegate, String latestJSBundleFile) throws IllegalAccessException {
- try {
- JSBundleLoader latestJSBundleLoader;
- if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
- latestJSBundleLoader = JSBundleLoader.createAssetLoader(getReactApplicationContext(), latestJSBundleFile, false);
- } else {
- latestJSBundleLoader = JSBundleLoader.createFileLoader(latestJSBundleFile);
- }
-
- Field bundleLoaderField = reactHostDelegate.getClass().getDeclaredField("jsBundleLoader");
- bundleLoaderField.setAccessible(true);
- bundleLoaderField.set(reactHostDelegate, latestJSBundleLoader);
- } catch (Exception e) {
- CodePushUtils.log("Unable to set JSBundle of ReactHostDelegate - CodePush may not support this version of React Native");
- throw new IllegalAccessException("Could not setJSBundle");
- }
- }
-
private void loadBundle() {
clearLifecycleEventListener();
- // ReactNative core components are changed on new architecture.
- if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
- try {
- DevSupportManager devSupportManager = null;
- ReactHost reactHost = resolveReactHost();
- if (reactHost != null) {
- devSupportManager = reactHost.getDevSupportManager();
- }
- boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
-
- mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
- } catch(Exception e) {
- // If we got error in out reflection we should clear debug cache anyway.
- mCodePush.clearDebugCacheIfNeeded(false);
- }
-
- try {
- // #1) Get the ReactHost instance, which is what includes the
- // logic to reload the current React context.
- final ReactHost reactHost = resolveReactHost();
- if (reactHost == null) {
- return;
- }
-
- String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
+ try {
+ DevSupportManager devSupportManager = resolveDevSupportManager();
+ boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
+ mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
+ } catch (Exception e) {
+ mCodePush.clearDebugCacheIfNeeded(false);
+ }
- // #2) Update the locally stored JS bundle file path
- setJSBundle(getReactHostDelegate((ReactHostImpl) reactHost), latestJSBundleFile);
+ try {
+ String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
+ Object reactHost = resolveReactHost();
- // #3) Get the context creation method
- try {
- reactHost.reload("CodePush triggers reload");
+ if (reactHost != null) {
+ setReactHostBundleLoader(reactHost, latestJSBundleFile);
+ if (reloadReactHost(reactHost)) {
mCodePush.initializeUpdateAfterRestart();
- } catch (Exception e) {
- // The recreation method threw an unknown exception
- // so just simply fallback to restarting the Activity (if it exists)
- loadBundleLegacy();
- }
-
- } catch (Exception e) {
- // Our reflection logic failed somewhere
- // so fall back to restarting the Activity (if it exists)
- CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
- loadBundleLegacy();
- }
-
- } else {
-
- try {
- DevSupportManager devSupportManager = null;
- ReactInstanceManager reactInstanceManager = resolveInstanceManager();
- if (reactInstanceManager != null) {
- devSupportManager = reactInstanceManager.getDevSupportManager();
- }
- boolean isLiveReloadEnabled = isLiveReloadEnabled(devSupportManager);
-
- mCodePush.clearDebugCacheIfNeeded(isLiveReloadEnabled);
- } catch(Exception e) {
- // If we got error in out reflection we should clear debug cache anyway.
- mCodePush.clearDebugCacheIfNeeded(false);
- }
-
- try {
- // #1) Get the ReactInstanceManager instance, which is what includes the
- // logic to reload the current React context.
- final ReactInstanceManager instanceManager = resolveInstanceManager();
- if (instanceManager == null) {
return;
}
+ }
- String latestJSBundleFile = mCodePush.getJSBundleFileInternal(mCodePush.getAssetsBundleFileName());
-
- // #2) Update the locally stored JS bundle file path
- setJSBundle(instanceManager, latestJSBundleFile);
-
- // #3) Get the context creation method and fire it on the UI thread (which RN enforces)
- new Handler(Looper.getMainLooper()).post(new Runnable() {
- @Override
- public void run() {
- try {
- // We don't need to resetReactRootViews anymore
- // due the issue https://github.com/facebook/react-native/issues/14533
- // has been fixed in RN 0.46.0
- //resetReactRootViews(instanceManager);
-
- instanceManager.recreateReactContextInBackground();
- mCodePush.initializeUpdateAfterRestart();
- } catch (Exception e) {
- // The recreation method threw an unknown exception
- // so just simply fallback to restarting the Activity (if it exists)
- loadBundleLegacy();
- }
- }
- });
-
- } catch (Exception e) {
- // Our reflection logic failed somewhere
- // so fall back to restarting the Activity (if it exists)
- CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
+ final ReactInstanceManager instanceManager = resolveInstanceManager();
+ if (instanceManager == null) {
loadBundleLegacy();
+ return;
}
+ setJSBundle(instanceManager, latestJSBundleFile);
+ new Handler(Looper.getMainLooper()).post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ instanceManager.recreateReactContextInBackground();
+ mCodePush.initializeUpdateAfterRestart();
+ } catch (Exception e) {
+ loadBundleLegacy();
+ }
+ }
+ });
+ } catch (Exception e) {
+ CodePushUtils.log("Failed to load the bundle, falling back to restarting the Activity (if it exists). " + e.getMessage());
+ loadBundleLegacy();
}
}
@@ -284,13 +189,11 @@ private boolean isLiveReloadEnabled(DevSupportManager devSupportManager) {
return false;
}
- // This workaround has been implemented in order to fix https://github.com/facebook/react-native/issues/14533
- // resetReactRootViews allows to call recreateReactContextInBackground without any exceptions
- // This fix also relates to https://github.com/microsoft/react-native-code-push/issues/878
+ @SuppressWarnings("unused")
private void resetReactRootViews(ReactInstanceManager instanceManager) throws NoSuchFieldException, IllegalAccessException {
Field mAttachedRootViewsField = instanceManager.getClass().getDeclaredField("mAttachedRootViews");
mAttachedRootViewsField.setAccessible(true);
- List mAttachedRootViews = (List)mAttachedRootViewsField.get(instanceManager);
+ List mAttachedRootViews = (List) mAttachedRootViewsField.get(instanceManager);
for (ReactRootView reactRootView : mAttachedRootViews) {
reactRootView.removeAllViews();
reactRootView.setId(View.NO_ID);
@@ -299,44 +202,58 @@ private void resetReactRootViews(ReactInstanceManager instanceManager) throws No
}
private void clearLifecycleEventListener() {
- // Remove LifecycleEventListener to prevent infinite restart loop
if (mLifecycleEventListener != null) {
- getReactApplicationContext().removeLifecycleEventListener(mLifecycleEventListener);
+ reactContext.removeLifecycleEventListener(mLifecycleEventListener);
mLifecycleEventListener = null;
}
}
- // Use reflection to find the ReactInstanceManager. See #556 for a proposal for a less brittle way to approach this.
- private ReactInstanceManager resolveInstanceManager() throws NoSuchFieldException, IllegalAccessException {
+ private ReactInstanceManager resolveInstanceManager() {
ReactInstanceManager instanceManager = CodePush.getReactInstanceManager();
if (instanceManager != null) {
return instanceManager;
}
- final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
+ final Activity currentActivity = reactContext.getCurrentActivity();
if (currentActivity == null) {
return null;
}
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
- instanceManager = reactApplication.getReactNativeHost().getReactInstanceManager();
+ return reactApplication.getReactNativeHost().getReactInstanceManager();
+ }
- return instanceManager;
+ private DevSupportManager resolveDevSupportManager() {
+ Object reactHost = resolveReactHost();
+ if (reactHost != null) {
+ DevSupportManager devSupportManager = getDevSupportManagerFromReactHost(reactHost);
+ if (devSupportManager != null) {
+ return devSupportManager;
+ }
+ }
+
+ ReactInstanceManager instanceManager = resolveInstanceManager();
+ return instanceManager != null ? instanceManager.getDevSupportManager() : null;
}
- private ReactHost resolveReactHost() throws NoSuchFieldException, IllegalAccessException {
- ReactHost reactHost = CodePush.getReactHost();
+ private Object resolveReactHost() {
+ Object reactHost = CodePush.getReactHost();
if (reactHost != null) {
return reactHost;
}
- final Activity currentActivity = getReactApplicationContext().getCurrentActivity();
+ final Activity currentActivity = reactContext.getCurrentActivity();
if (currentActivity == null) {
return null;
}
ReactApplication reactApplication = (ReactApplication) currentActivity.getApplication();
- return reactApplication.getReactHost();
+ try {
+ Method getReactHostMethod = reactApplication.getClass().getMethod("getReactHost");
+ return getReactHostMethod.invoke(reactApplication);
+ } catch (Exception e) {
+ return null;
+ }
}
private void restartAppInternal(boolean onlyIfUpdateIsPending) {
@@ -365,8 +282,7 @@ private void restartAppInternal(boolean onlyIfUpdateIsPending) {
}
}
- @ReactMethod
- public void allow(Promise promise) {
+ void allow(Promise promise) {
CodePushUtils.log("Re-allowing restarts");
this._allowed = true;
@@ -378,37 +294,30 @@ public void allow(Promise promise) {
}
promise.resolve(null);
- return;
}
- @ReactMethod
- public void clearPendingRestart(Promise promise) {
+ void clearPendingRestart(Promise promise) {
this._restartQueue.clear();
promise.resolve(null);
- return;
}
- @ReactMethod
- public void disallow(Promise promise) {
+ void disallow(Promise promise) {
CodePushUtils.log("Disallowing restarts");
this._allowed = false;
promise.resolve(null);
- return;
}
- @ReactMethod
- public void restartApp(boolean onlyIfUpdateIsPending, Promise promise) {
+ void restartApp(boolean onlyIfUpdateIsPending, Promise promise) {
try {
restartAppInternal(onlyIfUpdateIsPending);
promise.resolve(null);
- } catch(CodePushUnknownException e) {
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
}
- @ReactMethod
- public void downloadUpdate(final ReadableMap updatePackage, final boolean notifyProgress, final Promise promise) {
+ void downloadUpdate(final ReadableMap updatePackage, final boolean notifyProgress, final Promise promise) {
AsyncTask asyncTask = new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
@@ -426,7 +335,6 @@ public void call(DownloadProgress downloadProgress) {
}
latestDownloadProgress = downloadProgress;
- // If the download is completed, synchronously send the last event.
if (latestDownloadProgress.isCompleted()) {
dispatchDownloadProgressEvent();
return;
@@ -437,7 +345,7 @@ public void call(DownloadProgress downloadProgress) {
}
hasScheduledNextFrame = true;
- getReactApplicationContext().runOnUiQueueThread(new Runnable() {
+ reactContext.runOnUiQueueThread(new Runnable() {
@Override
public void run() {
ReactChoreographer.getInstance().postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, new Choreographer.FrameCallback() {
@@ -455,7 +363,7 @@ public void doFrame(long frameTimeNanos) {
}
public void dispatchDownloadProgressEvent() {
- getReactApplicationContext()
+ reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(CodePushConstants.DOWNLOAD_PROGRESS_EVENT_NAME, latestDownloadProgress.createWritableMap());
}
@@ -479,29 +387,26 @@ public void dispatchDownloadProgressEvent() {
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- @ReactMethod
- public void getConfiguration(Promise promise) {
+ void getConfiguration(Promise promise) {
try {
- WritableMap configMap = Arguments.createMap();
+ WritableMap configMap = Arguments.createMap();
configMap.putString("appVersion", mCodePush.getAppVersion());
configMap.putString("clientUniqueId", mClientUniqueId);
configMap.putString("deploymentKey", mCodePush.getDeploymentKey());
configMap.putString("serverUrl", mCodePush.getServerUrl());
- // The binary hash may be null in debug builds
if (mBinaryContentsHash != null) {
configMap.putString(CodePushConstants.PACKAGE_HASH_KEY, mBinaryContentsHash);
}
promise.resolve(configMap);
- } catch(CodePushUnknownException e) {
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
}
- @ReactMethod
- public void getUpdateMetadata(final int updateState, final Promise promise) {
+ void getUpdateMetadata(final double updateState, final Promise promise) {
AsyncTask asyncTask = new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
@@ -520,43 +425,29 @@ protected Void doInBackground(Void... params) {
currentUpdateIsPending = mSettingsManager.isPendingUpdate(currentHash);
}
- if (updateState == CodePushUpdateState.PENDING.getValue() && !currentUpdateIsPending) {
- // The caller wanted a pending update
- // but there isn't currently one.
+ int updateStateValue = (int) updateState;
+ if (updateStateValue == CodePushUpdateState.PENDING.getValue() && !currentUpdateIsPending) {
promise.resolve(null);
- } else if (updateState == CodePushUpdateState.RUNNING.getValue() && currentUpdateIsPending) {
- // The caller wants the running update, but the current
- // one is pending, so we need to grab the previous.
+ } else if (updateStateValue == CodePushUpdateState.RUNNING.getValue() && currentUpdateIsPending) {
JSONObject previousPackage = mUpdateManager.getPreviousPackage();
-
if (previousPackage == null) {
promise.resolve(null);
return null;
}
-
promise.resolve(CodePushUtils.convertJsonObjectToWritable(previousPackage));
} else {
- // The current package satisfies the request:
- // 1) Caller wanted a pending, and there is a pending update
- // 2) Caller wanted the running update, and there isn't a pending
- // 3) Caller wants the latest update, regardless if it's pending or not
if (mCodePush.isRunningBinaryVersion()) {
- // This only matters in Debug builds. Since we do not clear "outdated" updates,
- // we need to indicate to the JS side that somehow we have a current update on
- // disk that is not actually running.
CodePushUtils.setJSONValueForKey(currentPackage, "_isDebugOnly", true);
}
- // Enable differentiating pending vs. non-pending updates
CodePushUtils.setJSONValueForKey(currentPackage, "isPending", currentUpdateIsPending);
promise.resolve(CodePushUtils.convertJsonObjectToWritable(currentPackage));
}
} catch (CodePushMalformedDataException e) {
- // We need to recover the app in case 'codepush.json' is corrupted
CodePushUtils.log(e.getMessage());
clearUpdates();
promise.resolve(null);
- } catch(CodePushUnknownException e) {
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
@@ -568,8 +459,7 @@ protected Void doInBackground(Void... params) {
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- @ReactMethod
- public void getNewStatusReport(final Promise promise) {
+ void getNewStatusReport(final Promise promise) {
AsyncTask asyncTask = new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
@@ -613,8 +503,8 @@ protected Void doInBackground(Void... params) {
}
}
- promise.resolve("");
- } catch(CodePushUnknownException e) {
+ promise.resolve(null);
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
@@ -625,8 +515,7 @@ protected Void doInBackground(Void... params) {
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- @ReactMethod
- public void installUpdate(final ReadableMap updatePackage, final int installMode, final int minimumBackgroundDuration, final Promise promise) {
+ void installUpdate(final ReadableMap updatePackage, final double installMode, final double minimumBackgroundDuration, final Promise promise) {
AsyncTask asyncTask = new AsyncTask() {
@Override
protected Void doInBackground(Void... params) {
@@ -637,23 +526,17 @@ protected Void doInBackground(Void... params) {
if (pendingHash == null) {
throw new CodePushUnknownException("Update package to be installed has no hash.");
} else {
- mSettingsManager.savePendingUpdate(pendingHash, /* isLoading */false);
+ mSettingsManager.savePendingUpdate(pendingHash, /* isLoading */ false);
}
- if (installMode == CodePushInstallMode.ON_NEXT_RESUME.getValue() ||
- // We also add the resume listener if the installMode is IMMEDIATE, because
- // if the current activity is backgrounded, we want to reload the bundle when
- // it comes back into the foreground.
- installMode == CodePushInstallMode.IMMEDIATE.getValue() ||
- installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
+ int installModeValue = (int) installMode;
+ if (installModeValue == CodePushInstallMode.ON_NEXT_RESUME.getValue()
+ || installModeValue == CodePushInstallMode.IMMEDIATE.getValue()
+ || installModeValue == CodePushInstallMode.ON_NEXT_SUSPEND.getValue()) {
- // Store the minimum duration on the native module as an instance
- // variable instead of relying on a closure below, so that any
- // subsequent resume-based installs could override it.
- CodePushNativeModule.this.mMinimumBackgroundDuration = minimumBackgroundDuration;
+ CodePushNativeModuleImpl.this.mMinimumBackgroundDuration = (int) minimumBackgroundDuration;
if (mLifecycleEventListener == null) {
- // Ensure we do not add the listener twice.
mLifecycleEventListener = new LifecycleEventListener() {
private Date lastPausedDate = null;
private Handler appSuspendHandler = new Handler(Looper.getMainLooper());
@@ -668,12 +551,10 @@ public void run() {
@Override
public void onHostResume() {
appSuspendHandler.removeCallbacks(loadBundleRunnable);
- // As of RN 36, the resume handler fires immediately if the app is in
- // the foreground, so explicitly wait for it to be backgrounded first
if (lastPausedDate != null) {
long durationInBackground = (new Date().getTime() - lastPausedDate.getTime()) / 1000;
- if (installMode == CodePushInstallMode.IMMEDIATE.getValue()
- || durationInBackground >= CodePushNativeModule.this.mMinimumBackgroundDuration) {
+ if (installModeValue == CodePushInstallMode.IMMEDIATE.getValue()
+ || durationInBackground >= CodePushNativeModuleImpl.this.mMinimumBackgroundDuration) {
CodePushUtils.log("Loading bundle on resume");
restartAppInternal(false);
}
@@ -682,12 +563,10 @@ public void onHostResume() {
@Override
public void onHostPause() {
- // Save the current time so that when the app is later
- // resumed, we can detect how long it was in the background.
lastPausedDate = new Date();
- if (installMode == CodePushInstallMode.ON_NEXT_SUSPEND.getValue() && mSettingsManager.isPendingUpdate(null)) {
- appSuspendHandler.postDelayed(loadBundleRunnable, minimumBackgroundDuration * 1000);
+ if (installModeValue == CodePushInstallMode.ON_NEXT_SUSPEND.getValue() && mSettingsManager.isPendingUpdate(null)) {
+ appSuspendHandler.postDelayed(loadBundleRunnable, CodePushNativeModuleImpl.this.mMinimumBackgroundDuration * 1000L);
}
}
@@ -696,12 +575,12 @@ public void onHostDestroy() {
}
};
- getReactApplicationContext().addLifecycleEventListener(mLifecycleEventListener);
+ reactContext.addLifecycleEventListener(mLifecycleEventListener);
}
}
- promise.resolve("");
- } catch(CodePushUnknownException e) {
+ promise.resolve(null);
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
@@ -713,8 +592,7 @@ public void onHostDestroy() {
asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- @ReactMethod
- public void isFailedUpdate(String packageHash, Promise promise) {
+ void isFailedUpdate(String packageHash, Promise promise) {
try {
promise.resolve(mSettingsManager.isFailedHash(packageHash));
} catch (CodePushUnknownException e) {
@@ -723,8 +601,7 @@ public void isFailedUpdate(String packageHash, Promise promise) {
}
}
- @ReactMethod
- public void getLatestRollbackInfo(Promise promise) {
+ void getLatestRollbackInfo(Promise promise) {
try {
JSONObject latestRollbackInfo = mSettingsManager.getLatestRollbackInfo();
if (latestRollbackInfo != null) {
@@ -738,8 +615,7 @@ public void getLatestRollbackInfo(Promise promise) {
}
}
- @ReactMethod
- public void setLatestRollbackInfo(String packageHash, Promise promise) {
+ void setLatestRollbackInfo(String packageHash, Promise promise) {
try {
mSettingsManager.setLatestRollbackInfo(packageHash);
promise.resolve(null);
@@ -749,53 +625,46 @@ public void setLatestRollbackInfo(String packageHash, Promise promise) {
}
}
- @ReactMethod
- public void isFirstRun(String packageHash, Promise promise) {
+ void isFirstRun(String packageHash, Promise promise) {
try {
boolean isFirstRun = mCodePush.didUpdate()
&& packageHash != null
&& packageHash.length() > 0
&& packageHash.equals(mUpdateManager.getCurrentPackageHash());
promise.resolve(isFirstRun);
- } catch(CodePushUnknownException e) {
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
}
- @ReactMethod
- public void notifyApplicationReady(Promise promise) {
+ void notifyApplicationReady(Promise promise) {
try {
mSettingsManager.removePendingUpdate();
- promise.resolve("");
- } catch(CodePushUnknownException e) {
+ promise.resolve(null);
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
promise.reject(e);
}
}
- @ReactMethod
- public void recordStatusReported(ReadableMap statusReport) {
+ void recordStatusReported(ReadableMap statusReport) {
try {
mTelemetryManager.recordStatusReported(statusReport);
- } catch(CodePushUnknownException e) {
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
}
}
- @ReactMethod
- public void saveStatusReportForRetry(ReadableMap statusReport) {
+ void saveStatusReportForRetry(ReadableMap statusReport) {
try {
mTelemetryManager.saveStatusReportForRetry(statusReport);
- } catch(CodePushUnknownException e) {
+ } catch (CodePushUnknownException e) {
CodePushUtils.log(e);
}
}
- @ReactMethod
- // Replaces the current bundle with the one downloaded from removeBundleUrl.
- // It is only to be used during tests. No-ops if the test configuration flag is not set.
- public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
+ void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
try {
if (mCodePush.isUsingTestConfiguration()) {
try {
@@ -804,45 +673,113 @@ public void downloadAndReplaceCurrentBundle(String remoteBundleUrl) {
throw new CodePushUnknownException("Unable to replace current bundle", e);
}
}
- } catch(CodePushUnknownException | CodePushMalformedDataException e) {
+ } catch (CodePushUnknownException | CodePushMalformedDataException e) {
CodePushUtils.log(e);
}
}
- /**
- * This method clears CodePush's downloaded updates.
- * It is needed to switch to a different deployment if the current deployment is more recent.
- * Note: we don’t recommend to use this method in scenarios other than that (CodePush will call
- * this method automatically when needed in other cases) as it could lead to unpredictable
- * behavior.
- */
- @ReactMethod
- public void clearUpdates() {
+ void clearUpdates() {
CodePushUtils.log("Clearing updates.");
mCodePush.clearUpdates();
}
- @ReactMethod
- public void addListener(String eventName) {
- // Set up any upstream listeners or background tasks as necessary
+ void addListener(String eventName) {
+ // no-op
+ }
+
+ void removeListeners(double count) {
+ // no-op
+ }
+
+ private JSBundleLoader createBundleLoader(String latestJSBundleFile) {
+ if (latestJSBundleFile.toLowerCase().startsWith("assets://")) {
+ return JSBundleLoader.createAssetLoader(reactContext, latestJSBundleFile, false);
+ }
+
+ return JSBundleLoader.createFileLoader(latestJSBundleFile);
}
- @ReactMethod
- public void removeListeners(Integer count) {
- // Remove upstream listeners, stop unnecessary background tasks
+ private DevSupportManager getDevSupportManagerFromReactHost(Object reactHost) {
+ try {
+ Method method = reactHost.getClass().getMethod("getDevSupportManager");
+ Object devSupportManager = method.invoke(reactHost);
+ return devSupportManager instanceof DevSupportManager ? (DevSupportManager) devSupportManager : null;
+ } catch (Exception e) {
+ return null;
+ }
}
- public ReactHostDelegate getReactHostDelegate(ReactHostImpl reactHostImpl) {
+ private Object getReactHostDelegate(Object reactHost) {
try {
- Class> clazz = reactHostImpl.getClass();
- Field field = clazz.getDeclaredField("mReactHostDelegate");
- field.setAccessible(true);
+ Method method = reactHost.getClass().getMethod("getReactHostDelegate");
+ return method.invoke(reactHost);
+ } catch (Exception ignored) {
+ }
- // Get the value of the field for the provided instance
- return (ReactHostDelegate) field.get(reactHostImpl);
- } catch (NoSuchFieldException | IllegalAccessException e) {
- e.printStackTrace();
+ try {
+ Field field = findField(reactHost.getClass(), "mReactHostDelegate", "reactHostDelegate");
+ if (field == null) {
+ return null;
+ }
+
+ field.setAccessible(true);
+ return field.get(reactHost);
+ } catch (Exception e) {
return null;
}
}
+
+ private void setReactHostBundleLoader(Object reactHost, String latestJSBundleFile) throws IllegalAccessException {
+ Object reactHostDelegate = getReactHostDelegate(reactHost);
+ if (reactHostDelegate == null) {
+ throw new IllegalAccessException("Could not resolve ReactHostDelegate");
+ }
+
+ try {
+ Field bundleLoaderField = findField(reactHostDelegate.getClass(), "jsBundleLoader", "mJsBundleLoader");
+ if (bundleLoaderField == null) {
+ throw new NoSuchFieldException("jsBundleLoader");
+ }
+
+ bundleLoaderField.setAccessible(true);
+ bundleLoaderField.set(reactHostDelegate, createBundleLoader(latestJSBundleFile));
+ } catch (Exception e) {
+ CodePushUtils.log("Unable to set JSBundle of ReactHostDelegate - CodePush may not support this version of React Native");
+ throw new IllegalAccessException("Could not setJSBundle");
+ }
+ }
+
+ private boolean reloadReactHost(Object reactHost) {
+ try {
+ Method reloadWithReasonMethod = reactHost.getClass().getMethod("reload", String.class);
+ reloadWithReasonMethod.invoke(reactHost, "CodePush triggers reload");
+ return true;
+ } catch (Exception ignored) {
+ }
+
+ try {
+ Method reloadMethod = reactHost.getClass().getMethod("reload");
+ reloadMethod.invoke(reactHost);
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ private Field findField(Class> type, String... fieldNames) {
+ Class> currentType = type;
+ while (currentType != null) {
+ for (String fieldName : fieldNames) {
+ try {
+ return currentType.getDeclaredField(fieldName);
+ } catch (NoSuchFieldException ignored) {
+ }
+ }
+
+ currentType = currentType.getSuperclass();
+ }
+
+ return null;
+ }
}
+
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushNotInitializedException.java b/android/src/main/java/com/microsoft/codepush/react/CodePushNotInitializedException.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushNotInitializedException.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushNotInitializedException.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java b/android/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushTelemetryManager.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUnknownException.java b/android/src/main/java/com/microsoft/codepush/react/CodePushUnknownException.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushUnknownException.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushUnknownException.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java b/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateState.java b/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateState.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateState.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushUpdateState.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java b/android/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushUpdateUtils.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUtils.java b/android/src/main/java/com/microsoft/codepush/react/CodePushUtils.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/CodePushUtils.java
rename to android/src/main/java/com/microsoft/codepush/react/CodePushUtils.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgress.java b/android/src/main/java/com/microsoft/codepush/react/DownloadProgress.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/DownloadProgress.java
rename to android/src/main/java/com/microsoft/codepush/react/DownloadProgress.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java b/android/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java
rename to android/src/main/java/com/microsoft/codepush/react/DownloadProgressCallback.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/FileUtils.java b/android/src/main/java/com/microsoft/codepush/react/FileUtils.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/FileUtils.java
rename to android/src/main/java/com/microsoft/codepush/react/FileUtils.java
diff --git a/android/src/main/java/com/microsoft/codepush/react/ReactHostHolder.java b/android/src/main/java/com/microsoft/codepush/react/ReactHostHolder.java
new file mode 100644
index 000000000..864443732
--- /dev/null
+++ b/android/src/main/java/com/microsoft/codepush/react/ReactHostHolder.java
@@ -0,0 +1,5 @@
+package com.microsoft.codepush.react;
+
+public interface ReactHostHolder {
+ Object getReactHost();
+}
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java b/android/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java
rename to android/src/main/java/com/microsoft/codepush/react/ReactInstanceHolder.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/SettingsManager.java b/android/src/main/java/com/microsoft/codepush/react/SettingsManager.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/SettingsManager.java
rename to android/src/main/java/com/microsoft/codepush/react/SettingsManager.java
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java b/android/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java
similarity index 100%
rename from android/app/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java
rename to android/src/main/java/com/microsoft/codepush/react/TLSSocketFactory.java
diff --git a/package-lock.json b/package-lock.json
index 28b7ac609..2fd7fc28a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"xcode": "3.0.1"
},
"devDependencies": {
+ "@srcpush/plugin-testing-framework": "0.1.0",
"@types/assert": "^1.5.2",
"@types/mkdirp": "^1.0.1",
"@types/mocha": "^9.0.0",
@@ -25,7 +26,6 @@
"@types/q": "^1.5.4",
"archiver": "latest",
"body-parser": "latest",
- "code-push-plugin-testing-framework": "file:./code-push-plugin-testing-framework",
"express": "^5.1.0",
"mkdirp": "latest",
"mocha": "^11.7.2",
@@ -39,7 +39,7 @@
},
"code-push-plugin-testing-framework": {
"version": "0.0.1",
- "dev": true,
+ "extraneous": true,
"license": "MIT",
"dependencies": {
"@types/uuid": "^8.3.1",
@@ -306,6 +306,20 @@
"node": ">=14"
}
},
+ "node_modules/@srcpush/plugin-testing-framework": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/@srcpush/plugin-testing-framework/-/plugin-testing-framework-0.1.0.tgz",
+ "integrity": "sha512-yb4qkTxfc9+WxhJYkcRV8ss3E5eEKUSxLnvqkQfMQU61T/ROQN+g+oLz17Tc0jzTjqj7xDkhrihIAAGeAXGT1w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "archiver": "^7.0.1",
+ "express": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=18.18"
+ }
+ },
"node_modules/@tootallnate/quickjs-emscripten": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
@@ -344,12 +358,6 @@
"integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==",
"dev": true
},
- "node_modules/@types/uuid": {
- "version": "8.3.4",
- "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz",
- "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==",
- "dev": true
- },
"node_modules/@xmldom/xmldom": {
"version": "0.8.10",
"resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.10.tgz",
@@ -769,12 +777,6 @@
"dev": true,
"optional": true
},
- "node_modules/base-64": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/base-64/-/base-64-1.0.0.tgz",
- "integrity": "sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==",
- "dev": true
- },
"node_modules/base64-js": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
@@ -1056,15 +1058,6 @@
"integrity": "sha512-bNFETTG/pM5ryzQ9Ad0lJOTa6HWD/YsScAR3EnCPZRPlQh77JocYktSHOUHelyhm8IARL+o4c4F1bP5KVOjiRA==",
"license": "MIT"
},
- "node_modules/charenc": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
- "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
"node_modules/chokidar": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
@@ -1165,10 +1158,6 @@
"yazl": "^2.5.1"
}
},
- "node_modules/code-push-plugin-testing-framework": {
- "resolved": "code-push-plugin-testing-framework",
- "link": true
- },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -1334,15 +1323,6 @@
"node": ">= 8"
}
},
- "node_modules/crypt": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
- "integrity": "sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
"node_modules/data-uri-to-buffer": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
@@ -2258,12 +2238,6 @@
"node": ">= 0.10"
}
},
- "node_modules/is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
- "dev": true
- },
"node_modules/is-core-module": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
@@ -2511,17 +2485,6 @@
"node": ">= 0.4"
}
},
- "node_modules/md5": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz",
- "integrity": "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==",
- "dev": true,
- "dependencies": {
- "charenc": "0.0.2",
- "crypt": "0.0.2",
- "is-buffer": "~1.1.6"
- }
- },
"node_modules/media-typer": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz",
@@ -2642,7 +2605,6 @@
"integrity": "sha512-mTT6RgopEYABzXWFx+GcJ+ZQ32kp4fMf0xvpZIIfSq9Z8lC/++MtcCnQ9t5FP2veYEP95FIYSvW+U9fV4xrlig==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"browser-stdout": "^1.3.1",
"chokidar": "^4.0.1",
@@ -2674,22 +2636,6 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
- "node_modules/mocha-junit-reporter": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/mocha-junit-reporter/-/mocha-junit-reporter-2.2.1.tgz",
- "integrity": "sha512-iDn2tlKHn8Vh8o4nCzcUVW4q7iXp7cC4EB78N0cDHIobLymyHNwe0XG8HEHHjc3hJlXm0Vy6zcrxaIhnI2fWmw==",
- "dev": true,
- "dependencies": {
- "debug": "^4.3.4",
- "md5": "^2.3.0",
- "mkdirp": "^3.0.0",
- "strip-ansi": "^6.0.1",
- "xml": "^1.0.1"
- },
- "peerDependencies": {
- "mocha": ">=2.2.5"
- }
- },
"node_modules/mocha/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
@@ -2924,15 +2870,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/p-try": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
- "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/pac-proxy-agent": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz",
@@ -3318,220 +3255,6 @@
"node": ">=10.0.0"
}
},
- "node_modules/replace": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/replace/-/replace-1.2.2.tgz",
- "integrity": "sha512-C4EDifm22XZM2b2JOYe6Mhn+lBsLBAvLbK8drfUQLTfD1KYl/n3VaW/CDju0Ny4w3xTtegBpg8YNSpFJPUDSjA==",
- "dev": true,
- "dependencies": {
- "chalk": "2.4.2",
- "minimatch": "3.0.5",
- "yargs": "^15.3.1"
- },
- "bin": {
- "replace": "bin/replace.js",
- "search": "bin/search.js"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/replace/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/replace/node_modules/camelcase": {
- "version": "5.3.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
- "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/replace/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/replace/node_modules/cliui": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
- "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^6.2.0"
- }
- },
- "node_modules/replace/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/replace/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "node_modules/replace/node_modules/decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/replace/node_modules/find-up": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
- "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
- "dev": true,
- "dependencies": {
- "locate-path": "^5.0.0",
- "path-exists": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/replace/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/replace/node_modules/locate-path": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
- "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
- "dev": true,
- "dependencies": {
- "p-locate": "^4.1.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/replace/node_modules/minimatch": {
- "version": "3.0.5",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz",
- "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/replace/node_modules/p-limit": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
- "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
- "dev": true,
- "dependencies": {
- "p-try": "^2.0.0"
- },
- "engines": {
- "node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/replace/node_modules/p-locate": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
- "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
- "dev": true,
- "dependencies": {
- "p-limit": "^2.2.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/replace/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/replace/node_modules/y18n": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz",
- "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==",
- "dev": true
- },
- "node_modules/replace/node_modules/yargs": {
- "version": "15.4.1",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz",
- "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==",
- "dev": true,
- "dependencies": {
- "cliui": "^6.0.0",
- "decamelize": "^1.2.0",
- "find-up": "^4.1.0",
- "get-caller-file": "^2.0.1",
- "require-directory": "^2.1.1",
- "require-main-filename": "^2.0.0",
- "set-blocking": "^2.0.0",
- "string-width": "^4.2.0",
- "which-module": "^2.0.0",
- "y18n": "^4.0.0",
- "yargs-parser": "^18.1.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/replace/node_modules/yargs-parser": {
- "version": "18.1.3",
- "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
- "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==",
- "dev": true,
- "dependencies": {
- "camelcase": "^5.0.0",
- "decamelize": "^1.2.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@@ -3541,12 +3264,6 @@
"node": ">=0.10.0"
}
},
- "node_modules/require-main-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
- "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==",
- "dev": true
- },
"node_modules/requires-port": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
@@ -3790,12 +3507,6 @@
"node": ">= 18"
}
},
- "node_modules/set-blocking": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
- "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
- "dev": true
- },
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -4489,7 +4200,6 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"dev": true,
- "peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
@@ -4498,13 +4208,6 @@
"node": ">=4.2.0"
}
},
- "node_modules/undici-types": {
- "version": "7.18.2",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
- "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
- "license": "MIT",
- "optional": true
- },
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
@@ -4536,15 +4239,6 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
- "node_modules/uuid": {
- "version": "8.3.2",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
- "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
- "dev": true,
- "bin": {
- "uuid": "dist/bin/uuid"
- }
- },
"node_modules/vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@@ -4578,12 +4272,6 @@
"node": ">= 8"
}
},
- "node_modules/which-module": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz",
- "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==",
- "dev": true
- },
"node_modules/workerpool": {
"version": "9.3.4",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-9.3.4.tgz",
@@ -4648,12 +4336,6 @@
"uuid": "dist/bin/uuid"
}
},
- "node_modules/xml": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz",
- "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==",
- "dev": true
- },
"node_modules/xmlbuilder": {
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz",
diff --git a/package.json b/package.json
index 587530705..809f6eda6 100644
--- a/package.json
+++ b/package.json
@@ -55,9 +55,9 @@
"@types/mocha": "^9.0.0",
"@types/node": "^14.0.27",
"@types/q": "^1.5.4",
+ "@srcpush/plugin-testing-framework": "0.1.0",
"archiver": "latest",
"body-parser": "latest",
- "code-push-plugin-testing-framework": "file:./code-push-plugin-testing-framework",
"express": "^5.1.0",
"mkdirp": "latest",
"mocha": "^11.7.2",
@@ -82,4 +82,4 @@
"postunlink": "node node_modules/@srcpush/react-native-code-push/scripts/postunlink/run"
}
}
-}
\ No newline at end of file
+}
diff --git a/react-native.config.js b/react-native.config.js
index 386fbf066..a251afec3 100644
--- a/react-native.config.js
+++ b/react-native.config.js
@@ -2,9 +2,10 @@ module.exports = {
dependency: {
platforms: {
android: {
+ sourceDir: './android',
+ packageImportPath: 'import com.microsoft.codepush.react.CodePush;',
packageInstance:
- "CodePush.getInstance(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)",
- sourceDir: './android/app',
+ 'CodePush.getInstance(getResources().getString(R.string.CodePushDeploymentKey), getApplicationContext(), BuildConfig.DEBUG)',
}
}
}
diff --git a/test/plugin-testing-framework-compat.d.ts b/test/plugin-testing-framework-compat.d.ts
new file mode 100644
index 000000000..55dcc7781
--- /dev/null
+++ b/test/plugin-testing-framework-compat.d.ts
@@ -0,0 +1,191 @@
+declare module "@srcpush/plugin-testing-framework" {
+ import Q = require("q");
+
+ namespace Platform {
+ interface IPlatform {
+ getName(): string;
+ getCommandLineFlagName(): string;
+ getServerUrl(): string;
+ getEmulatorManager(): IEmulatorManager;
+ getDefaultDeploymentKey(): string;
+ }
+
+ interface IEmulatorManager {
+ getTargetEmulator(): Q.Promise;
+ bootEmulator(restartEmulators: boolean): Q.Promise;
+ launchInstalledApplication(appId: string): Q.Promise;
+ endRunningApplication(appId: string): Q.Promise;
+ restartApplication(appId: string): Q.Promise;
+ resumeApplication(appId: string, delayBeforeResumingMs?: number): Q.Promise;
+ prepareEmulatorForTest(appId: string): Q.Promise;
+ uninstallApplication(appId: string): Q.Promise;
+ }
+
+ class Android implements IPlatform {
+ constructor(emulatorManager: IEmulatorManager);
+ getName(): string;
+ getCommandLineFlagName(): string;
+ getServerUrl(): string;
+ getEmulatorManager(): IEmulatorManager;
+ getDefaultDeploymentKey(): string;
+ }
+
+ class IOS implements IPlatform {
+ constructor(emulatorManager: IEmulatorManager);
+ getName(): string;
+ getCommandLineFlagName(): string;
+ getServerUrl(): string;
+ getEmulatorManager(): IEmulatorManager;
+ getDefaultDeploymentKey(): string;
+ }
+
+ class AndroidEmulatorManager implements IEmulatorManager {
+ getTargetEmulator(): Q.Promise;
+ bootEmulator(restartEmulators: boolean): Q.Promise;
+ launchInstalledApplication(appId: string): Q.Promise;
+ endRunningApplication(appId: string): Q.Promise;
+ restartApplication(appId: string): Q.Promise;
+ resumeApplication(appId: string, delayBeforeResumingMs?: number): Q.Promise;
+ prepareEmulatorForTest(appId: string): Q.Promise;
+ uninstallApplication(appId: string): Q.Promise;
+ }
+
+ class IOSEmulatorManager implements IEmulatorManager {
+ getTargetEmulator(): Q.Promise;
+ bootEmulator(restartEmulators: boolean): Q.Promise;
+ launchInstalledApplication(appId: string): Q.Promise;
+ endRunningApplication(appId: string): Q.Promise;
+ restartApplication(appId: string): Q.Promise;
+ resumeApplication(appId: string, delayBeforeResumingMs?: number): Q.Promise;
+ prepareEmulatorForTest(appId: string): Q.Promise;
+ uninstallApplication(appId: string): Q.Promise;
+ }
+ }
+
+ namespace PluginTestingFramework {
+ function initializeTests(
+ projectManager: ProjectManager,
+ supportedTargetPlatforms: Platform.IPlatform[],
+ describeTests: (projectManager: ProjectManager, targetPlatform: Platform.IPlatform) => void
+ ): void;
+ }
+
+ class ProjectManager {
+ static DEFAULT_APP_VERSION: string;
+ getPluginName(): string;
+ setupProject(projectDirectory: string, templatePath: string, appName: string, appNamespace: string, version?: string): Q.Promise;
+ setupScenario(projectDirectory: string, appId: string, templatePath: string, jsPath: string, targetPlatform: Platform.IPlatform, version?: string): Q.Promise;
+ createUpdateArchive(projectDirectory: string, targetPlatform: Platform.IPlatform, isDiff?: boolean): Q.Promise;
+ preparePlatform(projectDirectory: string, targetPlatform: Platform.IPlatform): Q.Promise;
+ cleanupAfterPlatform(projectDirectory: string, targetPlatform: Platform.IPlatform): Q.Promise;
+ runApplication(projectDirectory: string, targetPlatform: Platform.IPlatform): Q.Promise;
+ }
+
+ function setupTestRunScenario(projectManager: ProjectManager, targetPlatform: Platform.IPlatform, scenarioJsPath: string, version?: string): Q.Promise;
+ function setupUpdateScenario(projectManager: ProjectManager, targetPlatform: Platform.IPlatform, scenarioJsPath: string, version: string): Q.Promise;
+
+ namespace ServerUtil {
+ let server: any;
+ let updateResponse: any;
+ let testMessageResponse: any;
+ let testMessageCallback: (requestBody: any) => void;
+ let updateCheckCallback: (requestBody: any) => void;
+ let updatePackagePath: string;
+
+ function setupServer(targetPlatform: Platform.IPlatform): void;
+ function cleanupServer(): void;
+ function createDefaultResponse(): any;
+ function createUpdateResponse(mandatory?: boolean, targetPlatform?: Platform.IPlatform, randomHash?: boolean): any;
+ function expectTestMessages(expectedMessages: any[]): Q.Promise;
+
+ class TestMessage {
+ static CHECK_UP_TO_DATE: string;
+ static CHECK_UPDATE_AVAILABLE: string;
+ static CHECK_ERROR: string;
+ static DOWNLOAD_SUCCEEDED: string;
+ static DOWNLOAD_ERROR: string;
+ static UPDATE_INSTALLED: string;
+ static INSTALL_ERROR: string;
+ static DEVICE_READY_AFTER_UPDATE: string;
+ static UPDATE_FAILED_PREVIOUSLY: string;
+ static NOTIFY_APP_READY_SUCCESS: string;
+ static NOTIFY_APP_READY_FAILURE: string;
+ static SKIPPED_NOTIFY_APPLICATION_READY: string;
+ static SYNC_STATUS: string;
+ static RESTART_SUCCEEDED: string;
+ static RESTART_FAILED: string;
+ static PENDING_PACKAGE: string;
+ static CURRENT_PACKAGE: string;
+ static SYNC_UP_TO_DATE: number;
+ static SYNC_UPDATE_INSTALLED: number;
+ static SYNC_UPDATE_IGNORED: number;
+ static SYNC_ERROR: number;
+ static SYNC_IN_PROGRESS: number;
+ static SYNC_CHECKING_FOR_UPDATE: number;
+ static SYNC_AWAITING_USER_ACTION: number;
+ static SYNC_DOWNLOADING_PACKAGE: number;
+ static SYNC_INSTALLING_UPDATE: number;
+ }
+
+ class TestMessageResponse {
+ static SKIP_NOTIFY_APPLICATION_READY: string;
+ }
+
+ class AppMessage {
+ message: string;
+ args: any[];
+ constructor(message: string, args: any[]);
+ static fromString(message: string): AppMessage;
+ }
+ }
+
+ class TestBuilder {
+ static describe: {
+ (description: string, spec: () => void, scenarioPath?: string): void;
+ only(description: string, spec: () => void, scenarioPath?: string): void;
+ skip(description: string, spec: () => void, scenarioPath?: string): void;
+ };
+ static it: {
+ (expectation: string, isCoreTest: boolean, assertion: (done: Mocha.Done) => void): void;
+ only(expectation: string, isCoreTest: boolean, assertion: (done: Mocha.Done) => void): void;
+ skip(expectation: string, isCoreTest: boolean, assertion: (done: Mocha.Done) => void): void;
+ };
+ }
+
+ namespace TestConfig {
+ const TestAppName: string;
+ const TestNamespace: string;
+ const AcquisitionSDKPluginName: string;
+ const templatePath: string;
+ const thisPluginInstallString: string;
+ const testRunDirectory: string;
+ const updatesDirectory: string;
+ const onlyRunCoreTests: boolean;
+ const shouldSetup: boolean;
+ const restartEmulators: boolean;
+ const isOldArchitecture: boolean;
+ }
+
+ class TestUtil {
+ static ANDROID_KEY_PLACEHOLDER: string;
+ static IOS_KEY_PLACEHOLDER: string;
+ static SERVER_URL_PLACEHOLDER: string;
+ static INDEX_JS_PLACEHOLDER: string;
+ static CODE_PUSH_APP_VERSION_PLACEHOLDER: string;
+ static CODE_PUSH_TEST_APP_NAME_PLACEHOLDER: string;
+ static CODE_PUSH_APP_ID_PLACEHOLDER: string;
+ static PLUGIN_VERSION_PLACEHOLDER: string;
+
+ static readMochaCommandLineOption(optionName: string, defaultValue?: string): string;
+ static readMochaCommandLineFlag(optionName: string): boolean;
+ static getProcessOutput(command: string, options?: any): Q.Promise;
+ static getPluginName(): string;
+ static getPluginVersion(): string;
+ static replaceString(filePath: string, regex: string, replacement: string): void;
+ static copyFile(source: string, destination: string, overwrite: boolean): Q.Promise;
+ static archiveFolder(sourceFolder: string, targetFolder: string, archivePath: string, isDiff: boolean): Q.Promise;
+ static resolveBooleanVariables(variable: string | undefined): boolean;
+ }
+
+ export { Platform, PluginTestingFramework, ProjectManager, setupTestRunScenario, setupUpdateScenario, ServerUtil, TestBuilder, TestConfig, TestUtil };
+}
diff --git a/test/test.ts b/test/test.ts
index a9c7861b9..e7bdd75e3 100644
--- a/test/test.ts
+++ b/test/test.ts
@@ -6,12 +6,10 @@ import mkdirp = require("mkdirp");
import path = require("path");
import slash = require("slash");
-import { Platform, PluginTestingFramework, ProjectManager, setupTestRunScenario, setupUpdateScenario, ServerUtil, TestBuilder, TestConfig, TestUtil } from "code-push-plugin-testing-framework";
+import { Platform, PluginTestingFramework, ProjectManager, setupTestRunScenario, setupUpdateScenario, ServerUtil, TestBuilder, TestConfig, TestUtil } from "@srcpush/plugin-testing-framework";
import Q = require("q");
-import {isOldArchitecture} from "code-push-plugin-testing-framework/script/testConfig";
-
//////////////////////////////////////////////////////////////////////////////////////////
// Create the platforms to run the tests on.
diff --git a/tsconfig.json b/tsconfig.json
index be6029c2c..aea1c6257 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,6 +8,7 @@
"noImplicitAny": true,
"noEmitOnError": true,
"moduleResolution": "node",
+ "skipLibCheck": true,
"sourceMap": true,
"rootDir": "test",
"outDir": "bin",
@@ -16,4 +17,4 @@
"exclude": [
"Examples"
]
-}
\ No newline at end of file
+}