Skip to content

Commit

Permalink
Merge pull request #496 from embrace-io/lucas/set_bundle_id_code_push
Browse files Browse the repository at this point in the history
Add method to notify CodePush update into RN internal interface.
  • Loading branch information
lucaslabari committed Mar 4, 2024
2 parents f31bbb3 + d74b3aa commit 5b7f82c
Show file tree
Hide file tree
Showing 13 changed files with 189 additions and 27 deletions.
1 change: 1 addition & 0 deletions embrace-android-sdk/api/embrace-android-sdk.api
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ public abstract interface class io/embrace/android/embracesdk/ReactNativeInterna
public abstract fun logRnAction (Ljava/lang/String;JJLjava/util/Map;ILjava/lang/String;)V
public abstract fun logRnView (Ljava/lang/String;)V
public abstract fun logUnhandledJsException (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
public abstract fun setCacheableJavaScriptBundleUrl (Landroid/content/Context;Ljava/lang/String;Z)V
public abstract fun setJavaScriptBundleUrl (Landroid/content/Context;Ljava/lang/String;)V
public abstract fun setJavaScriptPatchNumber (Ljava/lang/String;)V
public abstract fun setReactNativeSdkVersion (Ljava/lang/String;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,23 @@ public interface ReactNativeInternalInterface : EmbraceInternalInterface {

public fun setReactNativeVersionNumber(version: String?)

/**
* Sets the React Native Bundle URL.
* @param context the context
* @param url the JavaScript bundle URL
*/
public fun setJavaScriptBundleUrl(context: Context, url: String)

/**
* Sets the React Native Bundle URL, indicating if the bundle was updated or not.
* If it was updated, the bundle ID will be recomputed.
* If not, the bundle ID will be retrieved from cache.
* @param context the context
* @param url the JavaScript bundle URL
* @param didUpdate if the bundle was updated
*/
public fun setCacheableJavaScriptBundleUrl(context: Context, url: String, didUpdate: Boolean)

/**
* Logs a React Native Redux Action - this is not intended for public use.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,18 +96,11 @@ internal class ReactNativeInternalInterfaceImpl(
}

override fun setJavaScriptBundleUrl(context: Context, url: String) {
if (embrace.isStarted) {
if (framework != AppFramework.REACT_NATIVE) {
logger.logError(
"Failed to set Java Script bundle ID URL. Current framework: " +
framework.name + " is not React Native."
)
return
}
metadataService.setReactNativeBundleId(context, url)
} else {
logger.logSDKNotInitialized("set JavaScript bundle URL")
}
setJavaScriptBundleUrl(context, url, null)
}

override fun setCacheableJavaScriptBundleUrl(context: Context, url: String, didUpdate: Boolean) {
setJavaScriptBundleUrl(context, url, didUpdate)
}

override fun logRnAction(
Expand All @@ -124,4 +117,19 @@ internal class ReactNativeInternalInterfaceImpl(
override fun logRnView(screen: String) {
embrace.logRnView(screen)
}

private fun setJavaScriptBundleUrl(context: Context, url: String, didUpdate: Boolean? = null) {
if (embrace.isStarted) {
if (framework != AppFramework.REACT_NATIVE) {
logger.logError(
"Failed to set Java Script bundle ID URL. Current framework: " +
framework.name + " is not React Native."
)
return
}
metadataService.setReactNativeBundleId(context, url, didUpdate)
} else {
logger.logSDKNotInitialized("set JavaScript bundle URL")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -383,20 +383,25 @@ internal class EmbraceMetadataService private constructor(

override fun getEgl(): String? = egl

override fun setReactNativeBundleId(context: Context, jsBundleUrl: String?) {
override fun setReactNativeBundleId(context: Context, jsBundleUrl: String?, forceUpdate: Boolean?) {
val currentUrl = preferencesService.javaScriptBundleURL

if (currentUrl != jsBundleUrl) {
if (currentUrl != jsBundleUrl || forceUpdate == true) {
// It`s a new JS bundle URL, save the new value in preferences.
preferencesService.javaScriptBundleURL = jsBundleUrl

// Calculate the bundle ID for the new bundle URL
reactNativeBundleId = metadataBackgroundWorker.submit<String?> {
computeReactNativeBundleId(
val bundleId = computeReactNativeBundleId(
context,
jsBundleUrl,
buildInfo.buildId
)
if (forceUpdate != null) {
// if we have a value for forceUpdate, it means the bundleId is cacheable and we should store it.
preferencesService.javaScriptBundleId = bundleId
}
bundleId
}
}
}
Expand Down Expand Up @@ -501,11 +506,19 @@ internal class EmbraceMetadataService private constructor(
if (appFramework == AppFramework.REACT_NATIVE) {
reactNativeBundleId = metadataBackgroundWorker.submit<String?> {
val lastKnownJsBundleUrl = preferencesService.javaScriptBundleURL
computeReactNativeBundleId(
context,
lastKnownJsBundleUrl,
buildInfo.buildId
)
val lastKnownJsBundleId = preferencesService.javaScriptBundleId
if (!lastKnownJsBundleUrl.isNullOrEmpty() && !lastKnownJsBundleId.isNullOrEmpty()) {
// If we have a lastKnownJsBundleId, we use that as the last known bundle ID.
return@submit lastKnownJsBundleId
} else {
// If we don't have a lastKnownJsBundleId, we compute the bundle ID from the last known JS bundle URL.
// If the last known JS bundle URL is null, we set React Native bundle ID to the buildId.
return@submit computeReactNativeBundleId(
context,
lastKnownJsBundleUrl,
buildInfo.buildId
)
}
}
javaScriptPatchNumber = preferencesService.javaScriptPatchNumber
if (javaScriptPatchNumber != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,11 @@ internal interface MetadataService {

/**
* Sets React Native Bundle ID from a custom JavaScript Bundle URL.
* @param context the context
* @param jsBundleUrl the JavaScript bundle URL
* @param forceUpdate if the bundle was updated and we need to recompute the bundleId
*/
fun setReactNativeBundleId(context: Context, jsBundleUrl: String?)
fun setReactNativeBundleId(context: Context, jsBundleUrl: String?, forceUpdate: Boolean? = null)

/**
* Sets the Embrace Flutter SDK version
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,10 @@ internal class EmbracePreferencesService(
get() = prefs.getStringPreference(JAVA_SCRIPT_BUNDLE_URL_KEY)
set(value) = prefs.setStringPreference(JAVA_SCRIPT_BUNDLE_URL_KEY, value)

override var javaScriptBundleId: String?
get() = prefs.getStringPreference(JAVA_SCRIPT_BUNDLE_ID_KEY)
set(value) = prefs.setStringPreference(JAVA_SCRIPT_BUNDLE_ID_KEY, value)

override var rnSdkVersion: String?
get() = prefs.getStringPreference(REACT_NATIVE_SDK_VERSION_KEY)
set(value) = prefs.setStringPreference(REACT_NATIVE_SDK_VERSION_KEY, value)
Expand Down Expand Up @@ -372,6 +376,7 @@ internal class EmbracePreferencesService(
private const val LAST_CRASH_NUMBER_KEY = "io.embrace.crashnumber"
private const val LAST_NATIVE_CRASH_NUMBER_KEY = "io.embrace.nativecrashnumber"
private const val JAVA_SCRIPT_BUNDLE_URL_KEY = "io.embrace.jsbundle.url"
private const val JAVA_SCRIPT_BUNDLE_ID_KEY = "io.embrace.jsbundle.id"
private const val JAVA_SCRIPT_PATCH_NUMBER_KEY = "io.embrace.javascript.patch"
private const val REACT_NATIVE_VERSION_KEY = "io.embrace.reactnative.version"
private const val REACT_NATIVE_SDK_VERSION_KEY = "io.embrace.reactnative.sdk.version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ internal interface PreferencesService {
*/
var javaScriptBundleURL: String?

/**
* Last javaScript bundle ID.
*/
var javaScriptBundleId: String?

/**
* Embrace sdk version.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,44 @@ internal class ReactNativeInternalInterfaceImplTest {
}
}

@Test
fun testSetCacheableJavaScriptBundleUrl() {
impl = ReactNativeInternalInterfaceImpl(
embrace,
mockk(),
REACT_NATIVE,
preferencesService,
crashService,
metadataService,
logger
)

every { embrace.isStarted } returns true
impl.setCacheableJavaScriptBundleUrl(context, "index.android.bundle", true)
// Test that the metadata service was called with the correct parameters
assertEquals("index.android.bundle", metadataService.fakeReactNativeBundleId)
assertEquals(true, metadataService.forceUpdate)
}

@Test
fun testSetJavaScriptBundleURLForOtherOTAs() {
impl = ReactNativeInternalInterfaceImpl(
embrace,
mockk(),
REACT_NATIVE,
preferencesService,
crashService,
metadataService,
logger
)

every { embrace.isStarted } returns true
impl.setJavaScriptBundleUrl(context, "index.android.bundle")
// Test that the metadata service was called with the correct parameters
assertEquals("index.android.bundle", metadataService.fakeReactNativeBundleId)
assertEquals(null, metadataService.forceUpdate)
}

@Test
fun testLogUnhandledJsException() {
every { embrace.isStarted } returns true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ internal class EmbraceMetadataReactNativeTest {
assertEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
}

@Test
fun `test React Native bundle ID from preference if jsBundleIdUrl is a new value`() {
preferencesService.javaScriptBundleURL = "oldJavaScriptBundleURL"
val metadataService = getMetadataService()

metadataService.setReactNativeBundleId(context, "newJavaScriptBundleURL")
assertEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
}

@Test
fun `test React Native bundle ID url as Asset`() {
val bundleIdFile = Files.createTempFile("bundle-test", ".temp").toFile()
Expand All @@ -115,15 +124,69 @@ internal class EmbraceMetadataReactNativeTest {

val metadataService = getMetadataService()
metadataService.setReactNativeBundleId(context, "assets:https://index.android.bundle")
// get the react native Bundle ID once to call the lazy property
metadataService.getReactNativeBundleId()

verify(exactly = 1) { assetManager.open(eq("index.android.bundle")) }

assertNotEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
assertEquals("D41D8CD98F00B204E9800998ECF8427E", metadataService.getReactNativeBundleId())
}

@Test
fun `test React Native bundle ID url as Asset with forceUpdate param in true`() {
val bundleIdFile = Files.createTempFile("bundle-test", ".temp").toFile()
val inputStream = FileInputStream(bundleIdFile)
preferencesService.javaScriptBundleURL = null
preferencesService.javaScriptBundleId = null

every { context.assets } returns assetManager
every { assetManager.open(any()) } returns inputStream

val metadataService = getMetadataService()
metadataService.setReactNativeBundleId(context, "assets:https://index.android.bundle", true)

verify(exactly = 1) { assetManager.open(eq("index.android.bundle")) }

assertNotEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
assertEquals("D41D8CD98F00B204E9800998ECF8427E", metadataService.getReactNativeBundleId())
assertEquals("D41D8CD98F00B204E9800998ECF8427E", preferencesService.javaScriptBundleId)
}

@Test
fun `test React Native bundle ID url as Asset with forceUpdate param in false`() {
val bundleIdFile = Files.createTempFile("bundle-test", ".temp").toFile()
val inputStream = FileInputStream(bundleIdFile)
preferencesService.javaScriptBundleURL = "assets:https://index.android.bundle"
preferencesService.javaScriptBundleId = "persistedBundleId"

every { context.assets } returns assetManager
every { assetManager.open(any()) } returns inputStream

val metadataService = getMetadataService()
metadataService.setReactNativeBundleId(context, "assets:https://index.android.bundle", false)

assertNotEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
assertEquals("persistedBundleId", metadataService.getReactNativeBundleId())
assertEquals("persistedBundleId", preferencesService.javaScriptBundleId)
}

@Test
fun `test React Native bundle ID url as Asset with forceUpdate param being null`() {
val bundleIdFile = Files.createTempFile("bundle-test", ".temp").toFile()
val inputStream = FileInputStream(bundleIdFile)
preferencesService.javaScriptBundleURL = null
preferencesService.javaScriptBundleId = null

every { context.assets } returns assetManager
every { assetManager.open(any()) } returns inputStream

val metadataService = getMetadataService()
metadataService.setReactNativeBundleId(context, "assets:https://index.android.bundle", null)

assertNotEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
assertEquals("D41D8CD98F00B204E9800998ECF8427E", metadataService.getReactNativeBundleId())
assertEquals(null, preferencesService.javaScriptBundleId)
}

@Test
fun `test React Native bundle ID url as a custom file`() {
val bundleIdFile = Files.createTempFile("index.android.bundle", "temp").toFile()
Expand All @@ -132,9 +195,6 @@ internal class EmbraceMetadataReactNativeTest {
context,
bundleIdFile.absolutePath
)
// get the react native Bundle ID once to call the lazy property
metadataService.getReactNativeBundleId()

assertNotEquals(buildInfo.buildId, metadataService.getReactNativeBundleId())
assertEquals("D41D8CD98F00B204E9800998ECF8427E", metadataService.getReactNativeBundleId())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ internal class EmbraceMetadataServiceTest {
every { preferencesService.unityBuildIdNumber }.returns(null)
every { preferencesService.rnSdkVersion }.returns(null)
every { preferencesService.javaScriptPatchNumber }.returns(null)
every { preferencesService.javaScriptBundleURL }.returns(null)
every { preferencesService.javaScriptBundleId }.returns(null)
every { MetadataUtils.appEnvironment(any()) }.returns("UNKNOWN")

val metadataService = getReactNativeMetadataService()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ internal class FakeMetadataService(sessionId: String? = null) : MetadataService
var fakeAppId: String = "o0o0o"
var fakeDeviceId: String = "07D85B44E4E245F4A30E559BFC0D07FF"
var fakeReactNativeBundleId: String? = "fakeReactNativeBundleId"
var forceUpdate: Boolean? = null
var fakeFlutterSdkVersion: String? = "fakeFlutterSdkVersion"
var fakeDartVersion: String? = "fakeDartVersion"
var fakeRnSdkVersion: String? = "fakeRnSdkVersion"
Expand Down Expand Up @@ -96,8 +97,9 @@ internal class FakeMetadataService(sessionId: String? = null) : MetadataService

override fun getAppState(): String = appState

override fun setReactNativeBundleId(context: Context, jsBundleUrl: String?) {
override fun setReactNativeBundleId(context: Context, jsBundleUrl: String?, forceUpdate: Boolean?) {
fakeReactNativeBundleId = jsBundleUrl
this.forceUpdate = forceUpdate
}

override fun setEmbraceFlutterSdkVersion(version: String?) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ internal class FakePreferenceService(
override var backgroundActivityEnabled: Boolean = false,
override var dartSdkVersion: String? = null,
override var javaScriptBundleURL: String? = null,
override var javaScriptBundleId: String? = null,
override var rnSdkVersion: String? = null,
override var javaScriptPatchNumber: String? = null,
override var embraceFlutterSdkVersion: String? = null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,15 @@ internal class EmbracePreferencesServiceTest {
assertEquals(url, service.javaScriptBundleURL)
}

@Test
fun `test java script bundle id is saved`() {
assertNull(service.javaScriptBundleId)

val id = "0d48510589c0426b43f01a5fa060a333"
service.javaScriptBundleId = id
assertEquals(id, service.javaScriptBundleId)
}

@Test
fun `test java script patch number is saved`() {
assertNull(service.javaScriptPatchNumber)
Expand Down

0 comments on commit 5b7f82c

Please sign in to comment.