This open-source library allows you to integrate Mini App ecosystem into your iOS applications. Mini App SDK also facilitates communication between a mini app and the host app via a message bridge.
- Load MiniApp list
- Load MiniApp metadata
- Create a MiniApp view
- Facilitate communication between host app and mini app
And much more features which you can find them in Usage.
All the MiniApp files downloaded by the MiniApp iOS library are cached locally
This module supports iOS 11.0 and above. It has been tested on iOS 11.0 and above.
It is written in Swift 5.0 and can be used in compatible Xcode versions.
Mini App SDK is available through CocoaPods. To install it, simply add the following line to your Podfile:
pod 'MiniApp'
In your project configuration .plist you should add below Key/Value :
Key | Type | Description | Optional | Default |
---|---|---|---|---|
RASProjectId | String | Set your MiniApp host application project identifier |
NO | none |
RASProjectSubscriptionKey | String | Set your MiniApp subscription key |
NO | none |
RMAAPIEndpoint | String | Provide your own Base URL for API requests |
NO | none |
RMAHostAppUserAgentInfo | String | Host app name and version info that is appended in User agent. The value specified in the plist is retrieved only at the build time. |
YES | none |
If you don't want to use project settings, you have to pass this information one by one to the Config.userDefaults
using a Config.Key
as key:
Config.userDefaults?.set("MY_CUSTOM_ID", forKey: Config.Key.subscriptionKey.rawValue)
- Create a MiniApp
- Mini App Features
- Load the Mini App list
- Get a MiniAppInfo
- List Downloaded Mini apps
- Advanced Features
API Docs: MiniApp.create(appId:completionHandler:messageInterface:)
, MiniAppDisplayDelegate
MiniApp.create
is used to create a View
for displaying a specific mini app. You must provide the mini app ID which you wish to create (you can get the mini-app ID by Loading the Mini App List first). Calling MiniApp.create
will do the following:
- Checks with the platform what is the latest and published version of the mini app.
- Check if the latest version of the mini app has been already downloaded
- If yes, return the already downloaded mini app view.
- If not, download the latest version and then return the view
- If the device is disconnected from the internet and if the device already has a version of the mini app downloaded, then the already downloaded version will be returned immediately.
After calling MiniApp.create
, you will obtain an instance of MiniAppDisplayDelegate
which is the delegate of the Display module. You can call MiniAppDisplayDelegate.getMiniAppView
to obtain a View
for displaying the mini app.
The following is a simplified example:
MiniApp.shared().create(appId: String, completionHandler: { (result) in
switch result {
case .success(let miniAppDisplay):
let view = miniAppDisplay.getMiniAppView()
view.frame = self.view.bounds
self.view.addSubview(view)
case .failure(let error):
print("Error: ", error.localizedDescription)
}
}, messageInterface: self)
API Docs: MiniAppMessageDelegate
The MiniAppMessageDelegate
is used for passing messages between the Mini App (JavaScript) and the Host App (your native iOS App) and vice versa. Your App must provide the implementation for these functions.
Mini App SDK provides default implementation for few interfaces in MiniAppMessageDelegate
, however the Host app can still override them by implementing the interface in their side.
Method | Default |
---|---|
getUniqueId | 🚫 |
requestPermission | 🚫 |
requestCustomPermissions | ✅ |
shareContent | ✅ |
getUserName | 🚫 |
getProfilePhoto | 🚫 |
getAccessToken | 🚫 |
NOTE: Following code snippets is an example for implementing MiniAppMessageDelegate methods, you can add your own custom implementation or you can make use of the code which is provided in the Sample app.
API Docs: MiniAppUserInfoDelegate
extension ViewController: MiniAppMessageDelegate {
func getUniqueId() -> String {
guard let deviceId = UIDevice.current.identifierForVendor?.uuidString else {
return ""
}
return deviceId
}
}
API Docs: MiniAppMessageDelegate
extension ViewController: MiniAppMessageDelegate {
func requestPermission(permissionType: MiniAppPermissionType, completionHandler: @escaping (Result<String, Error>) -> Void) {
switch permissionType {
case .location:
let locStatus = CLLocationManager.authorizationStatus()
switch locStatus {
case .authorizedAlways, .authorizedWhenInUse:
completionHandler(.success("allowed"))
}
}
}
API Docs: MiniAppMessageDelegate
SDK has its own implementation to show the list of requested custom permissions. If you want to display your own UI for requesting custom permissions, you can do it by overriding the method like below,
extension ViewController: MiniAppMessageDelegate {
func requestCustomPermissions(
permissions: [MASDKCustomPermissionModel],
miniAppTitle: String,
completionHandler: @escaping (
Result<[MASDKCustomPermissionModel], Error>) -> Void) {
completionHandler(.success(permissions))
}
MiniApp iOS SDK supports list of Custom Permissions ( MiniAppCustomPermissionType
) and these can be stored and retrieved using the following public interfaces.
Custom permissions and its status can be retrieved using the following interface. getCustomPermissions
will return list of MASDKCustomPermissionModel
that contains the meta-info such as title and its granted status.
let miniAppPermissionsList = MiniApp.shared().getCustomPermissions(forMiniApp: miniAppId)
Custom permissions for a mini app is cached by the SDK and you can use the following interface to store and retrieve it when you need.
MiniApp.shared().setCustomPermissions(forMiniApp: String, permissionList: [MASDKCustomPermissionModel])
API Docs: MiniAppShareContentDelegate
By default, Mini App iOS SDK can open its own controller for content sharing. If you want to override this, you just have to implement the shareContent(info: MiniAppShareContent, completionHandler: @escaping (Result<MASDKProtocolResponse, Error>) -> Void)
from MiniAppShareContentDelegate
, which is part of MiniAppMessageDelegate
.
extension ViewController: MiniAppMessageDelegate {
func shareContent(info: MiniAppShareContent,
completionHandler: @escaping (
Result<String, Error>) -> Void) {
let activityController = UIActivityViewController(activityItems: [info.messageContent], applicationActivities: nil)
present(activityController, animated: true, completion: nil)
completionHandler(.success("SUCCESS"))
}
}
API Docs: MiniAppUserInfoDelegate
Get the User profile related details using 'MiniAppMessageDelegate'. The following delegates/interfaces will be called only if the user has allowed respective Custom permissions
Retrieve user name of the User
extension ViewController: MiniAppMessageDelegate {
func getUserName() -> String? {
// Implementation to return the User name
return ""
}
}
Retrieve Profile Photo of the User
extension ViewController: MiniAppMessageDelegate {
func getProfilePhoto() -> String? {
// Implementation to return the Profile photo URI
return ""
}
}
Retrieve access token and expiry date
extension ViewController: MiniAppMessageDelegate {
func getAccessToken(miniAppId: String, completionHandler: @escaping (Result<MATokenInfo, MASDKCustomPermissionError>) -> Void) {
completionHandler(.success(.init(accessToken: "ACCESS_TOKEN", expirationDate: Date())))
}
}
API Docs: MiniApp.list
MiniApp library calls are done via the MiniApp.shared()
singleton with or without a MiniAppSdkConfig
instance (you can get the current one with Config.getCurrent()
). If you don't provide a config instance, values in custom iOS target properties will be used by default.
MiniApp.shared().list { (result) in
...
}
or
MiniApp.shared(with: Config.getCurrent()).list { (result) in
...
}
API Docs: MiniApp.info
MiniApp.shared().info(miniAppId: miniAppID) { (result) in
...
}
or
MiniApp.shared(with: Config.getCurrent()).info(miniAppId: miniAppID) { (result) in
...
}
API Docs: MiniApp.listDownloadedWithCustomPermissions
Gets the list of downloaded Mini apps info and associated custom permissions status
MiniApp.shared().listDownloadedWithCustomPermissions()
API Docs: MiniAppSdkConfig
Along with Mini app features, Mini app SDK does provides more customization for the user. Some of the more customizable features are below,
Every call to the API can be done with default parameters retrieved from the project .plist configuration file, or by providing a MiniAppSdkConfig
object during the call. Here is a simple example class we use to create the configuration in samples below:
class Config: NSObject {
class func getCurrent() -> MiniAppSdkConfig {
return MiniAppSdkConfig(baseUrl: "https://your.custom.url"
rasAppId: "your_RAS_App_id",
subscriptionKey: "your_subscription_key",
hostAppVersion: "your_custom_version",
isTestMode: true")
}
}
NOTE: RMAHostAppUserAgentInfo
cannot be configured at run time.
API Docs: MiniAppNavigationConfig
MiniApp iOS SDK provides a fully customizable way to implement a navigation interface inside your html pages with a MiniAppNavigationConfig
object. The class takes 3 arguments:
navigationBarVisibility
:- never = the UI will never be shown
- auto = navigation UI is only shown when a back or forward action is available
- always = navigation UI is always present
navigationDelegate
: A delegate that will receive MiniApp view instructions about available navigation options. It will also receive taps on external links.customNavigationView
: A view implementingMiniAppNavigationDelegate
that will be overlayed to the bottom of the MiniApp view
let navConfig = MiniAppNavigationConfig(
navigationBarVisibility: .always,
navigationDelegate: myNavigationDelegate,
customNavigationView: mCustomView)
MiniApp.shared(with: Config.getCurrent(), navigationSettings: navConfig).info(miniAppId: miniAppID) { (result) in
...
}
API Docs: MiniAppNavigationConfig
By default MiniApp iOS SDK will open external links into a separate modal controller when tapped. MiniAppNavigationDelegate
implements a method that allows to override this behaviour and provide your own external links management. Here is an example of implementation:
extension ViewController: MiniAppNavigationDelegate {
func miniAppNavigation(shouldOpen url: URL, with externalLinkResponseHandler: @escaping (URL) -> Void) {
// Getting your custom viewcontroller
if let viewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "ExternalWebviewController") as? ExternalWebViewController {
viewController.currentURL = url
viewController.miniAppExternalUrlLoader = MiniAppExternalUrlLoader(webViewController: viewController, responseHandler: externalLinkResponseHandler)
self.presentedViewController?.present(viewController, animated: true)
}
}
...
}
The externalLinkResponseHandler
closure allows you to give a feedback as an URL to the SDK, for example when the controller is closed or when a custom scheme link is tapped. This closure can be passed to a MiniAppExternalUrlLoader
object that will provide a method to test an URL and return the appropriate decision for a WKNavigationDelegate
method, and if you provided a controller it will be dismissed automatically. Here is an example following previous example:
extension ExternalWebViewController: WKNavigationDelegate {
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
self.currentURL = self.webView.url
}
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(miniAppExternalUrlLoader?.shouldOverrideURLLoading(navigationAction.request.url) ?? .allow)
}
}
You can choose to give orientation lock control to mini apps. However, this requires you to add some code to your AppDelegate
which could have an affect on your entire App. If you do not wish to do this, please see the section "Allow only full screen videos to change orientation".
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
if #available(iOS 12, *) {
if window?.isKeyWindow != true {
return .all
}
}
if MiniApp.MAOrientationLock.isEmpty {
return .all
} else {
return MiniApp.MAOrientationLock
}
}
You can add the following if you want to enable videos to change orientation. Note that if you do not wish to add code to AppDelegate
as in the above example, you can still allow videos inside the mini app to use landscape mode even when your App is locked to portrait mode and vice versa.
import AVKit
extension AVPlayerViewController {
open override var supportedInterfaceOrientations: UIInterfaceOrientationMask {
if MiniApp.MAOrientationLock.isEmpty {
return .all
} else {
return MiniApp.MAOrientationLock
}
}
}
See the full CHANGELOG.