Skip to content

Commit 1922d58

Browse files
committed
Android: opt-in flag for bsdiff patches
1 parent aeee55a commit 1922d58

4 files changed

Lines changed: 47 additions & 8 deletions

File tree

android/app/src/main/java/com/microsoft/codepush/react/CodePush.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ public static String getServiceUrl() {
7070
private CodePush(String deploymentKey, Context context, boolean isDebugMode) {
7171
mContext = context.getApplicationContext();
7272

73-
mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath());
73+
boolean enableDeltaUpdates = getBooleanCustomPropertyFromStringsIfExist("EnableDeltaUpdates", false);
74+
mUpdateManager = new CodePushUpdateManager(context.getFilesDir().getAbsolutePath(), enableDeltaUpdates);
7475
mTelemetryManager = new CodePushTelemetryManager(mContext);
7576
mDeploymentKey = deploymentKey;
7677
mIsDebugMode = isDebugMode;
@@ -156,6 +157,17 @@ private String getCustomPropertyFromStringsIfExist(String propertyName) {
156157
return null;
157158
}
158159

160+
private boolean getBooleanCustomPropertyFromStringsIfExist(String propertyName, boolean defaultValue) {
161+
String packageName = mContext.getPackageName();
162+
int resId = mContext.getResources().getIdentifier("CodePush" + propertyName, "bool", packageName);
163+
164+
if (resId != 0) {
165+
return mContext.getResources().getBoolean(resId);
166+
}
167+
168+
return defaultValue;
169+
}
170+
159171
public void clearDebugCacheIfNeeded(boolean isLiveReloadEnabled) {
160172
// for checking if we use LiveReload mode. In this case we should not remove ReactNativeDevBundle.js file
161173
// because we get error with trying to get this after reloading. Issue: https://github.com/microsoft/react-native-code-push/issues/1272

android/app/src/main/java/com/microsoft/codepush/react/CodePushUpdateManager.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@
2424
public class CodePushUpdateManager {
2525

2626
private String mDocumentsDirectory;
27+
private boolean mEnableDeltaUpdates;
2728

28-
public CodePushUpdateManager(String documentsDirectory) {
29+
public CodePushUpdateManager(String documentsDirectory, boolean enableDeltaUpdates) {
2930
mDocumentsDirectory = documentsDirectory;
31+
mEnableDeltaUpdates = enableDeltaUpdates;
3032
}
3133

3234
private String getDownloadFilePath() {
@@ -276,15 +278,17 @@ void installDownloadedUpdate(JSONObject updatePackage, String expectedBundleFile
276278
if (isDiffUpdate) {
277279
// Run patching after copyNecessaryFilesFromCurrentPackage() so patched output overwrites
278280
// bytes copied in from the old package at the same paths.
279-
if (diffManifest.getVersion() == 2) {
281+
if (diffManifest.getVersion() > 2 || diffManifest.getVersion() < 1) {
282+
throw new IOException("Diff manifest version " + diffManifest.getVersion() + " is not supported by this SDK version.");
283+
} else if (diffManifest.getVersion() == 2 && !mEnableDeltaUpdates) {
284+
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.");
285+
} else if (diffManifest.getVersion() == 2) {
280286
String currentPackageFolderPath = getCurrentPackageFolderPath();
281287
if (currentPackageFolderPath == null) {
282288
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.");
283289
}
284290
BinaryDiffPatcher.applyBinaryDiffPatches(diffManifest, new File(currentPackageFolderPath), new File(unzippedFolderPath), new File(newUpdateFolderPath));
285291
FileUtils.deleteDirectoryAtPath(new File(newUpdateFolderPath, CodePushConstants.DIFF_PATCHES_FOLDER_NAME).getPath());
286-
} else if (diffManifest.getVersion() > 2) {
287-
throw new IOException("Diff manifest version " + diffManifest.getVersion() + " is not supported by this SDK version.");
288292
}
289293
}
290294

android/app/src/test/java/com/microsoft/codepush/react/CodePushUpdateManagerTest.kt

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ class CodePushUpdateManagerTest {
3636
logMock.close()
3737
}
3838

39-
private fun manager() =
40-
CodePushUpdateManager(tempFolder.newFolder("documents").absolutePath)
39+
private fun manager(enableDeltaUpdates: Boolean = false) =
40+
CodePushUpdateManager(tempFolder.newFolder("documents").absolutePath, enableDeltaUpdates)
4141

4242
private fun updatePackage(hash: String) = JSONObject().apply {
4343
put(CodePushConstants.PACKAGE_HASH_KEY, hash)
@@ -235,10 +235,28 @@ class CodePushUpdateManagerTest {
235235
}
236236
}
237237

238+
@Test
239+
fun installDownloadedUpdate_binaryDiffUpdateWhenDisabledOnClient_throwsIOException() {
240+
// Given
241+
val update = manager(enableDeltaUpdates = false)
242+
val downloadFile = zipOf(CodePushConstants.DIFF_MANIFEST_FILE_NAME to """{"version":2,"deletedFiles":[],"patchedFiles":{}}""")
243+
val pkg = updatePackage("hash9")
244+
val newUpdateFolderPath = update.getPackageFolderPath("hash9")
245+
val newUpdateMetadataPath = CodePushUtils.appendPathComponent(newUpdateFolderPath, CodePushConstants.PACKAGE_FILE_NAME)
246+
247+
// When / Then
248+
try {
249+
update.installDownloadedUpdate(pkg, "index.android.bundle", null, downloadFile, true, newUpdateFolderPath, newUpdateMetadataPath)
250+
fail("expected IOException")
251+
} catch (e: java.io.IOException) {
252+
assertTrue(e.message!!.contains("Received a binary diff update, but delta updates are not enabled on this client."))
253+
}
254+
}
255+
238256
@Test
239257
fun installDownloadedUpdate_binaryDiffUpdateWithNoCurrentPackageInstalled_throwsInvalidUpdateException() {
240258
// Given
241-
val update = manager()
259+
val update = manager(enableDeltaUpdates = true)
242260
val downloadFile = zipOf(CodePushConstants.DIFF_MANIFEST_FILE_NAME to """{"version":2,"deletedFiles":[],"patchedFiles":{}}""")
243261
val pkg = updatePackage("hash10")
244262
val newUpdateFolderPath = update.getPackageFolderPath("hash10")

docs/api-android.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ Since `autolinking` uses `react-native.config.js` to link plugins, constructors
1515
<string moduleConfig="true" name="CodePushServerUrl">https://yourcodepush.server.com</string>
1616
```
1717

18+
- **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:
19+
```xml
20+
<bool moduleConfig="true" name="CodePushEnableDeltaUpdates">true</bool>
21+
```
22+
1823
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`.
1924

2025
### Java API Reference (Android)

0 commit comments

Comments
 (0)