Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EMBR-4636 calculate react native bundle id #72

Merged
merged 6 commits into from
Sep 4, 2024

Conversation

jpmunz
Copy link
Contributor

@jpmunz jpmunz commented Aug 16, 2024

On Android and previously on iOS 5.x we would take the given file path/url and compute the md5 hash of the contents and set this as react_native_bundle_id on the session. See:

This attempts to recreate that functionality in our RN Swift native module

@jpmunz jpmunz requested review from ArielDemarco, TheMutsi and a team August 16, 2024 20:17
Copy link


// Check if we can re-use our last computed bundle ID, this is true only if the path hasn't changed and
// the file contents at that path haven't been modified since the last time we computed the ID
// TODO in ios 5.x and Android implementation we are just returning last.id in this case without checking modified at...is that correct?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ArielDemarco @TheMutsi this logic feels correct to me, e.g. only re-use the cache if the path is the same and the contents haven't been updated but it does deviate from the previous implementations so wanted to double-check

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM; I'd wait for @TheMutsi to see if there's nothing we're not considering

Copy link
Collaborator

@TheMutsi TheMutsi Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ArielDemarco can we move it to DispatchQueue bg? I think it could be very heavy

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that makes sense, I moved the calls to compute ID to background queues

Comment on lines 5 to 25
private struct LastBundleComputation: Codable {
private static let STORAGE_KEY = "EMBRACE_LAST_BUNDLE_COMPUTATION"
var path: String
var computedAt: Date?
var id: String

func store () {
if let encoded = try? JSONEncoder().encode(self) {
UserDefaults.standard.set(encoded, forKey: LastBundleComputation.STORAGE_KEY)
}
}

static func fromStorage() -> LastBundleComputation {
if let storedData = UserDefaults.standard.object(forKey: LastBundleComputation.STORAGE_KEY) as? Data,
let loaded = try? JSONDecoder().decode(LastBundleComputation.self, from: storedData) {
return loaded
}

return LastBundleComputation(path: "", computedAt: nil, id: "")
}
}
Copy link
Contributor

@ArielDemarco ArielDemarco Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd inject an "own" UserDefaults to prevent any problem in the future (like somebody migrating to another suite, or things like that).
The only bad thing about injecting it (and having an instance variable with an own userDefaults) is that you'll have to implement Codable manually.
So, i'd suggest something in the middle, like providing a utility to create an "Embrace" UserDefaults, like this:

extension UserDefaults {
    static var embrace: UserDefaults {
        UserDefaults(suiteName: "EmbraceReactNative") ?? .standard
    }
}

And then you can replace store and fromStorage using that utility:

func store () {
        if let encoded = try? JSONEncoder().encode(self) {
            UserDefaults.embrace.set(encoded, forKey: LastBundleComputation.STORAGE_KEY)
        }
    }

    static func fromStorage() -> LastBundleComputation {
        if let storedData = UserDefaults.embrace.object(forKey: LastBundleComputation.STORAGE_KEY) as? Data,
           let loaded = try? JSONDecoder().decode(LastBundleComputation.self, from: storedData) {
            return loaded
        }

        return LastBundleComputation(path: "", computedAt: nil, id: "")
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, added

@@ -799,3 +799,70 @@ class EmbraceSpansSDKNotStartedTests: XCTestCase {
}
}

class ComputeBundleIDTests: XCTestCase {
// https://nshipster.com/temporary-files/
Copy link
Contributor

@ArielDemarco ArielDemarco Aug 26, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably many of this tests under the hood, are using UserDefaults. UserDefaults writes things to disk (in a .plist file).
So, to prevent any kind of flakyness, i'd remove all things persisted in UserDefaults between tests. In order to achieve this (considering you've made this change, i'd add this code:

    override func tearDownWithError() throws {
          UserDefaults.standard.removePersistentDomain(forName: "EmbraceReactNative")
    }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added

Comment on lines 207 to 211
do {
#if canImport(CodePush)
guard let url = try CodePush.bundleURL() else {
reject("GET_CODEPUSH_BUNDLE_URL", "Error getting Codepush Bundle URL", nil)
return
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it's better not maintain "codepush" in a specific method, and just let the user set the javascript url if they are using codepush. @jpmunz what do you think? we can just remove this function and update the doc so we dont care if Codepush changes its name or method in the future

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd keep it as is for the purposes of the iOS 6.x migration but I'd like to revisit along with calculating the bundle ID altogether to see if we can reduce code here, noted in https://www.notion.so/embraceio/Rethink-maintaining-support-for-OTA-updates-efe0b4b089ba487d9ab6678b7f7ca491?pvs=4

@jpmunz jpmunz requested a review from TheMutsi August 28, 2024 14:37
@jpmunz
Copy link
Contributor Author

jpmunz commented Aug 28, 2024

@ArielDemarco @facostaembrace @TheMutsi a bit of a larger change in cf514f5 to get this working if you wanted to recheck the PR

previously when the RN ios module was written in objective-c we had wrapped the code push in a #if __has_include(<CodePush/CodePush.h>) directive to only run if the host app actually had code push. The equivalent #if canImport(CodePush) for Swift didn't work as code push isn't exposed as a Swift module.

Instead I ended up adding a new objective-c CodePushHelper class which all it does is wrap the call we need to grab the codepush url in that same directive we previously had or nil otherwise, then on the swift side we call into that without any compiler directives

@jpmunz jpmunz merged commit 890ed6d into 5.0 Sep 4, 2024
3 checks passed
@jpmunz jpmunz deleted the jpmunz/EMBR-4636-calculate-bundle-id branch September 4, 2024 14:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants