phrase / ios-sdk

Phrase Over the Air iOS SDK
https://phrase.com
Other
14 stars 3 forks source link

Phrase OTA on iOS native project, with KMP moko library #72

Open BVantur opened 1 month ago

BVantur commented 1 month ago

We are trying to integrate a Phrase localization service in our KMP project, which is targeting Android and iOS clients. We have managed to do that without a problem so far. We are using the moko-resources library for having shared resources within the shared module of the project and then we are using native-specific code for the setup of Phrase on iOS and Android native projects like it is done when one is using Phrase directly for Android or iOS clients.

Problems for us started when we tried to enable ourselves Over-the-air capability for the iOS project. For Android, this part works without a problem, but on the iOS side, we have problems getting the latest updated strings from the OTA feature visible in the app.

With our moko library, we are using this part in SwiftUI to get the string from resources: MR.strings().button_label_login.desc.localized()

With this code, we get locally saved text for that phrase key, but when we do some OTA updates for it we don't get the new text from it.

From our investigation, we found out that the problem lies in different bundles being created with the KMP project. There is a bundle of an iOS native project that stores OTA strings from the Phrase, and there is a bundle from Shared code, where we have our shared resources provided for Android and iOS clients. Direct MR.strings() call is using bundle from Shared code. When we are doing phrase pull that is using the Android way of creating XML files for the moko-resources library, those texts get updated for iOS directly in the build folder of the KMP project under this path:

project-name/shared/build/bin/iosSimulatorArm64/debugFramework/Shared.framework/ProjectName:shared.bundle/Contents/Resources/Base.lproj/Localizable.strings

But your library for Phrase OTA for iOS is adding those strings to the iOS native project bundle.

KMP is getting more and more popular and it would be great if you could either update your existing article on this topic with an explanation of how to integrate the OTA feature with the KMP project or prepare some other documentation for it.

If there is something we are missing with our setup let us know what we need to change to make our OTA integration work in our project.

BVantur commented 1 month ago

We solve that with our custom handling of fetching resources from the correct bundle. Whenever we tried to fetch from local data we used the moko bundle, and when we tried to use Phrase OTA data, we used the iOS app bundle.

theSoenke commented 3 weeks ago

Hi @BVantur, that's great to hear that both SDKs already work almost out of the box with KMP! Would you mind sharing the snippet that you use to use the correct bundle on iOS if that's possible? I would like to make sure that the KMP support is also properly documented

BVantur commented 3 weeks ago

Yeah, sure. We have a strange behavior in our app and I am not even sure if the above issue is a valid issue that we observed, In the end, what we needed to do with the iOS part of the app, is to use 2 different bundles in our LocalizationManager class.

For moko-based strings that we want to use in a case when there were no Phrase OTA texts present, we used this bundle: SharedRes.strings().__platformDetails.nsBundle

But for Phrase OTA texts we needed to use a bundle depending on the language with the URL like this:

let phrasePath = "com.phrase.phraseSDK/Translations/\(languageCode).lproj"
let languageDirectoryURL = applicationSupportDirectory.appendingPathComponent(phrasePath, isDirectory: true)
return languageDirectoryURL
Bundle(url: languageDirectoryURL)

In our LocalizationManager we are always trying to read Phrase OTA text first and if it doesn't exist we fall back to a bundle that has strings from the moko library.

I hope this comment will help someone who might end up in the same situation.