This library provides the following convenience extensions to the firebase remote config library:
- Strongly typed keys
- Posting notifications upon fetch and activate
- Combine support
- SwiftUI support
- Predefined keys and values for required and recommended updates
- CI scripts
Add pod 'EldersFirebaseRemoteConfig' to your Podfile
Currently the library is linked as static, because several firebase pods are linked statically. Because of this, SwiftUI previews are getting broken. Unfortunately cocoapods does not allow pushing a dynamic library pod that depends on static lirbary pods. If you wish to use the remote config SwiftUI previews, you have to use the alternative podspec that links as dynamic library, as following:
pod 'EldersFirebaseRemoteConfig', :git => 'https://github.com/Elders/EldersFirebaseRemoteConfig.git', :branch => 'fix_swiftui_previews'
You can leverage from strongly typed keys by extending the RemoteConfig.Key structure.
extension RemoteConfig.Key {
static let myCustomKey: Self = "myCustomKey"
}
Then you can set defaults.
RemoteConfig.remoteConfig().setDefaults([.myCustomKey: "my amazing value"])
And get values by using the defined key.
let value = RemoteConfig.remoteConfig().configValue(for: .myCustomKey)
The library swizzles the RemoteConfig object and posts notifications when calls to fetch and activate completes. The following notifications are defined, so you can observe them.
-
RemoteConfig.didFetchNotification- This notification is posted when a fetch call completes. It contains a userInfo with the following parameters:status- anNSNumbervalue ofFIRRemoteConfigFetchStatuserror- anErrorobject, if the fetch has failed
-
RemoteConfig.didActivateNotification- This notification is posted when an activate call completes. It contains a userInfo with the following parameters: -changed- aBOOLvalue wrapped inNSNumberthat isYESif there were changes to the remote config. OtherwiseNO. -error- anErrorobject, if the fetch has failed
The library adds support for Combine Publishers by extending the RemoteConfig type with the following functions
fetchPublisher(withExpirationDuration:)- corresponds tofetch(withExpirationDuration:completionHandler:)fetchPublisher()- corresponds tofetch(completionHandler:)activatePublisher()- corresponds toactivate(completion:)fetchAndActivatePublisher()- corresponds tofetchAndActivate(completionHandler:)
The library makes RemoteConfig conforming to ObservableObject protocol and publish changes upon fetch.
Now you can directly use RemoteConfig as @ObservedObject or as @EnvironmentObject in your SwiftUI project.
If you use RemoteConfig in your SwiftUI views, you can pass RemoteConfig.preview(withDefaults:) to your SwiftUI Previews.
This works by moking the RemoteConfig behaviour and allows it to work with the supplied default arguments.
The library defines a common structure and config access for required and recommended updates. These are just an optional interface that you can leverage on to quickly implement a force update mechanism in your app.
RemoteConfig.recommendedUpdate- represents an update of the app that is recommended for install.RemoteConfig.requiredUpdate- represents an update of the app that is required to install.
Both returns an instance of ApplicationUpdate. You can check whenever an update should be applied trough the isApplicable property.
This functionality basically compares your application version and delivers the defined updates from firebase remote config console.
It is wrapped around the convention that your app's CFBundleVersion is structured as X.Y.Z.a where:
- X is the major number
- Y is the minor number
- Z is the patch number
- a is the build number
How to make use of it?
Assuming your application's CFBundleVersion is 1.2.3.400
Go to firebase console and define a new remote config with one of the following keys:
- ios_required_update - use this key if you wish to publish a required update
- ios_recommended_update - use this key if you wish to publish a recommended update
The predefined keys are variables so you can override them if you wish to.
Then put the following value for the desired key.
{
"version": "1.2.3.500"
"download": "https://your.appstore.link/"
}
The download is a URL from where the update should be download. This is typically the AppStore link of your production app.
The version is the target version based on which the update is reported to be applicable.
In this example, the build number 500 is greater than the application's build number 400, so the update's isApplicable property will return true.
You can omit the build number in the remote config.
For example if you supply 1.2.3 - this will make isApplicable property will return false.
For example if you supply 1.2.4 - this will make isApplicable property will return true.
After you define and publish your remote config, you can check from your app whenever an update is available and applicable.
//check for required update
if let update = RemoteConfig.remoteConfig().requiredUpdate, update.isApplicable {
//show a blocking dialog to the user to inform him about the update
}
//check for recommended update
if let update = RemoteConfig.remoteConfig().recommendedUpdate, update.isApplicable {
//show a dialog to the user to inform him about the update
}
Depending on your needs, you can handle each use case accordingly, however here are some recommendations:
- if you use required updates - update the remote config and check for updates when your app becomes active - this way if the user manage to dismiss your blocking dialog, you can recover from it quickly
- if you use recommended updates - update the remote config and check for updates at least once when your app starts
- based on your needs, you can implement mechanism to allow users to postpone updates, etc ...
The library declares and delivers the remote config for the updates and check whenever an update is applicable - how you will interpret, use and handle these updates is in your hands.
The library also includes the following swift scripts which you can use on your CI. They work with a service account JSON key for authentication. For more information see Using OAuth 2.0 for Server to Server Applications
get_service_account_project_id- this scripts parses the service account JSON and outputs theproject_idgenerate_service_account_jws- this scripts generates the JWS needed to get access token from google, based on the service account JSONget_service_account_token_url- this scripts parses the service account JSON and outputs thetoken_uriset_remote_config_recommended_update- this script updates the firebase remote config with provided version, download url, platform and service account JSON