diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java
index ceafd545..d66e9a1b 100644
--- a/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java
+++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePush.java
@@ -70,7 +70,8 @@ public static String getServiceUrl() {
private CodePush(String deploymentKey, Context context, boolean isDebugMode) {
mContext = context.getApplicationContext();
- mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath());
+ boolean enableDeltaUpdates = getBooleanCustomPropertyFromStringsIfExist("EnableDeltaUpdates", false);
+ mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath(), enableDeltaUpdates);
mTelemetryManager = new CodePushTelemetryManager(mContext);
mDeploymentKey = deploymentKey;
mIsDebugMode = isDebugMode;
@@ -156,6 +157,17 @@ private String getCustomPropertyFromStringsIfExist(String propertyName) {
return null;
}
+ private boolean getBooleanCustomPropertyFromStringsIfExist(String propertyName, boolean defaultValue) {
+ String packageName = mContext.getPackageName();
+ int resId = mContext.getResources().getIdentifier("CodePush" + propertyName, "bool", packageName);
+
+ if (resId != 0) {
+ return mContext.getResources().getBoolean(resId);
+ }
+
+ return defaultValue;
+ }
+
public void clearDebugCacheIfNeeded(boolean isLiveReloadEnabled) {
// for checking if we use LiveReload mode. In this case we should not remove ReactNativeDevBundle.js file
// because we get error with trying to get this after reloading. Issue: https://github.com/microsoft/react-native-code-push/issues/1272
diff --git a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java
index 9daf8fc9..d85d119e 100644
--- a/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java
+++ b/android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java
@@ -24,9 +24,11 @@
public class CodePushUpdateManager {
private String mDocumentsDirectory;
+ private boolean mEnableDeltaUpdates;
- public CodePushUpdateManager(String documentsDirectory) {
+ public CodePushUpdateManager(String documentsDirectory, boolean enableDeltaUpdates) {
mDocumentsDirectory = documentsDirectory;
+ mEnableDeltaUpdates = enableDeltaUpdates;
}
private String getDownloadFilePath() {
@@ -276,15 +278,17 @@ void installDownloadedUpdate(JSONObject updatePackage, String expectedBundleFile
if (isDiffUpdate) {
// Run patching after copyNecessaryFilesFromCurrentPackage() so patched output overwrites
// bytes copied in from the old package at the same paths.
- if (diffManifest.getVersion() == 2) {
+ if (diffManifest.getVersion() > 2 || diffManifest.getVersion() < 1) {
+ throw new IOException("Diff manifest version " + diffManifest.getVersion() + " is not supported by this SDK version.");
+ } else if (diffManifest.getVersion() == 2 && !mEnableDeltaUpdates) {
+ throw new IOException("Received a binary diff update, but delta updates are not enabled on this client. Set CodePushEnableDeltaUpdates to true in strings.xml to enable them.");
+ } else if (diffManifest.getVersion() == 2) {
String currentPackageFolderPath = getCurrentPackageFolderPath();
if (currentPackageFolderPath == null) {
throw new CodePushInvalidUpdateException("Received a binary diff update, but no currently installed package exists to diff against (this is likely the first CodePush update for this app install). Diffing against the embedded app binary is not yet supported.");
}
BinaryDiffPatcher.applyBinaryDiffPatches(diffManifest, new File(currentPackageFolderPath), new File(unzippedFolderPath), new File(newUpdateFolderPath));
FileUtils.deleteDirectoryAtPath(new File(newUpdateFolderPath, CodePushConstants.DIFF_PATCHES_FOLDER_NAME).getPath());
- } else if (diffManifest.getVersion() > 2) {
- throw new IOException("Diff manifest version " + diffManifest.getVersion() + " is not supported by this SDK version.");
}
}
diff --git a/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerTest.kt b/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerTest.kt
index f4d15c13..c054eb9a 100644
--- a/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerTest.kt
+++ b/android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerTest.kt
@@ -36,8 +36,8 @@ class CodePushUpdateManagerTest {
logMock.close()
}
- private fun manager() =
- CodePushUpdateManager(tempFolder.newFolder("documents").absolutePath)
+ private fun manager(enableDeltaUpdates: Boolean = false) =
+ CodePushUpdateManager(tempFolder.newFolder("documents").absolutePath, enableDeltaUpdates)
private fun updatePackage(hash: String) = JSONObject().apply {
put(CodePushConstants.PACKAGE_HASH_KEY, hash)
@@ -235,10 +235,28 @@ class CodePushUpdateManagerTest {
}
}
+ @Test
+ fun installDownloadedUpdate_binaryDiffUpdateWhenDisabledOnClient_throwsIOException() {
+ // Given
+ val update = manager(enableDeltaUpdates = false)
+ val downloadFile = zipOf(CodePushConstants.DIFF_MANIFEST_FILE_NAME to """{"version":2,"deletedFiles":[],"patchedFiles":{}}""")
+ val pkg = updatePackage("hash9")
+ val newUpdateFolderPath = update.getPackageFolderPath("hash9")
+ val newUpdateMetadataPath = CodePushUtils.appendPathComponent(newUpdateFolderPath, CodePushConstants.PACKAGE_FILE_NAME)
+
+ // When / Then
+ try {
+ update.installDownloadedUpdate(pkg, "index.android.bundle", null, downloadFile, true, newUpdateFolderPath, newUpdateMetadataPath)
+ fail("expected IOException")
+ } catch (e: java.io.IOException) {
+ assertTrue(e.message!!.contains("Received a binary diff update, but delta updates are not enabled on this client."))
+ }
+ }
+
@Test
fun installDownloadedUpdate_binaryDiffUpdateWithNoCurrentPackageInstalled_throwsInvalidUpdateException() {
// Given
- val update = manager()
+ val update = manager(enableDeltaUpdates = true)
val downloadFile = zipOf(CodePushConstants.DIFF_MANIFEST_FILE_NAME to """{"version":2,"deletedFiles":[],"patchedFiles":{}}""")
val pkg = updatePackage("hash10")
val newUpdateFolderPath = update.getPackageFolderPath("hash10")
diff --git a/docs/api-android.md b/docs/api-android.md
index 092bfbb4..78b79fc2 100644
--- a/docs/api-android.md
+++ b/docs/api-android.md
@@ -15,6 +15,11 @@ Since `autolinking` uses `react-native.config.js` to link plugins, constructors
https://yourcodepush.server.com
```
+- **Enable Delta Updates** - switch for applying binary diff (bsdiff) patches during a diff update, off by default (at the moment). When disabled, only file-by-file diffing is applied (for example, skipping assets if only the main JS bundle changed, but that whole file is downloaded byte for byte). Add a `bool` resource named `CodePushEnableDeltaUpdates` to `strings.xml` to turn it on:
+ ```xml
+ true
+ ```
+
The Java API is made available by importing the `com.microsoft.codepush.react.CodePush` class into your `MainActivity.java` file, and consists of a single public class named `CodePush`.
### Java API Reference (Android)