Wrap native methods
This section describe how to create a native method handler for the Nabla SDK, so that you can call methods from your Dart code and have them implemented natively.
See the Flutter documentation for more details about how to write platform channels.
Android
Create NablaMethodCallHandler
NablaMethodCallHandler
In android/app/src/main/kotlin
create the NablaMethodHandler
:
class NablaMethodCallHandler(
private val activity: ComponentActivity,
private val methodChannel: MethodChannel,
) : MethodChannel.MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when(call.method) {
// TODO implement any method you'd like to wire here
else -> result.notImplemented()
}
}
}
Wire NablaMethodCallHandler
NablaMethodCallHandler
In the MainActivity
kotlin file (that should be in android/app/src/main/kotlin/your/package/name/MainActivity.kt
), register the method handler:
class MainActivity: FlutterFragmentActivity() {
private val delegate = AppCompatDelegate.create(this, null)
init {
addOnContextAvailableListener {
delegate.installViewFactory()
}
}
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
// Your other wiring here...
val channel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, "nabla")
channel.setMethodCallHandler(NablaMethodCallHandler(this, channel))
}
}
If you activity is of type
FlutterActivity
, change it toFlutterFragmentActivity
(io.flutter.embedding.android.FlutterFragmentActivity
)
iOS
Create NablaMethodCallHandler
NablaMethodCallHandler
In ios/Runner
create a new NablaMethodCallHandler.swift
file:
import Foundation
import Flutter
class NablaMethodCallHandler {
private let nablaChannel: FlutterMethodChannel
init(nablaChannel: FlutterMethodChannel) {
self.nablaChannel = nablaChannel
}
func handleCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
switch(call.method) {
// TODO implement any method you'd like to wire here
default: result(FlutterMethodNotImplemented)
}
}
}
Wire NablaMethodCallHandler
NablaMethodCallHandler
In ios/Runner
, open the AppDelegate.swift
file and wire the NablaMethodCallHandler
:
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
private var nablaMethodCallHandler: NablaMethodCallHandler!
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let nablaChannel = FlutterMethodChannel(name: "nabla", binaryMessenger: controller.binaryMessenger)
nablaMethodCallHandler = NablaMethodCallHandler(nablaChannel: nablaChannel)
nablaChannel.setMethodCallHandler(nablaMethodCallHandler.handleCall)
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Flutter
In your Dart code, you should now be able to call the native bridge, and can create a class to embed all of that code:
import 'package:flutter/services.dart';
class NablaNativeBridge {
static const _nablaChannel = MethodChannel('nabla');
// TODO implement Nabla methods here
}
The complete "initialize" example
This section provides a full example of how to wire the NablaClient.initialize
call via Dart code for Nabla SDK initialization:
Android:
class NablaMethodCallHandler(
private val activity: ComponentActivity,
private val methodChannel: MethodChannel,
) : MethodChannel.MethodCallHandler {
override fun onMethodCall(call: MethodCall, result: MethodChannel.Result) {
when(call.method) {
"initialize" -> handleInitialize(call, result)
else -> result.notImplemented()
}
}
private fun handleInitialize(call: MethodCall, result: MethodChannel.Result) {
try {
val apiKey = call.argument<String>("apiKey") ?: throw IllegalStateException("Null apiKey")
NablaClient.initialize(
modules = listOf(
NablaMessagingModule(), // if you want the messaging feature
NablaVideoCallModule(), // if you want to add video call capabilities
NablaSchedulingModule(), // if you want the scheduling feature
),
configuration = Configuration(
publicApiKey = apiKey,
),
sessionTokenProvider = { userId ->
withContext(Dispatchers.Main) {
suspendCancellableCoroutine { continuation ->
val resultHandler = object : MethodChannel.Result {
override fun success(result: Any?) {
val resultMap = result as? Map<Any, Any> ?: kotlin.run {
if (continuation.isActive) {
continuation.resumeWithException(IllegalStateException("Unable to parse user tokens result"))
}
return
}
val accessToken = resultMap["accessToken"] as? String
val refreshToken = resultMap["refreshToken"] as? String
if (accessToken == null || refreshToken == null) {
if (continuation.isActive) {
continuation.resumeWithException(IllegalStateException("Access or refresh token not found"))
}
return
}
if (continuation.isActive) {
continuation.resume(Result.success(AuthTokens(AccessToken(accessToken), RefreshToken(refreshToken))))
}
}
override fun error(
errorCode: String,
errorMessage: String?,
errorDetails: Any?
) {
if (continuation.isActive) {
continuation.resumeWithException(RuntimeException("$errorCode: $errorMessage ($errorDetails)"))
}
}
override fun notImplemented() {
if (continuation.isActive) {
continuation.resumeWithException(IllegalStateException("provideUserTokens channel method handler not implemented"))
}
}
}
methodChannel.invokeMethod(
"provideUserTokens",
mapOf(
"userId" to userId,
),
resultHandler,
)
}
}
}
)
result.success(null)
} catch (e: Exception) {
result.error("initialize", e.message, null)
}
}
}
iOS
import Foundation
import Flutter
import NablaCore
import NablaMessagingCore
import NablaScheduling
import NablaVideoCall
class NablaMethodCallHandler : SessionTokenProvider {
private let nablaChannel: FlutterMethodChannel
init(nablaChannel: FlutterMethodChannel) {
self.nablaChannel = nablaChannel
}
func handleCall(call: FlutterMethodCall, result: @escaping FlutterResult) {
switch(call.method) {
case "initialize": handleInitialize(call: call, result: result)
default: result(FlutterMethodNotImplemented)
}
}
private func handleInitialize(call: FlutterMethodCall, result: FlutterResult) {
guard let arguments = call.arguments as? Dictionary<String, AnyObject> else {
result(FlutterError(code: "initialize", message: "unable to get arguments", details: nil))
return
}
guard let apiKey = arguments["apiKey"] as? String else {
result(FlutterError(code: "initialize", message: "unable to get apiKey", details: nil))
return
}
NablaClient.initialize(
configuration: Configuration(apiKey: apiKey),
modules: [
NablaMessagingModule(), // if you want the messaging feature
NablaVideoCallModule(), // if you want to add video call capabilities
NablaSchedulingModule() // if you want the scheduling feature
],
sessionTokenProvider: self
)
result(nil)
}
func provideTokens(forUserId userId: String, completion: @escaping (NablaCore.AuthTokens?) -> Void) {
nablaChannel.invokeMethod("provideUserTokens", arguments: ["userId": userId]) { result in
if (result as? NSObject == FlutterMethodNotImplemented) {
completion(nil)
return
}
guard let dictResult = result as? Dictionary<String, String> else {
completion(nil)
return
}
guard let accessToken = dictResult["accessToken"] else {
completion(nil)
return
}
guard let refreshToken = dictResult["refreshToken"] else {
completion(nil)
return
}
completion(.init(accessToken: accessToken, refreshToken: refreshToken))
}
}
}
Flutter
class NablaNativeBridge {
static const _nablaChannel = MethodChannel('nabla');
NablaNativeBridge() {
_nablaChannel.setMethodCallHandler(_nablaNativeCallHandler);
}
Future<dynamic> _nablaNativeCallHandler(MethodCall call) async {
switch(call.method) {
case "provideUserTokens": return _provideUserTokens(call.arguments["userId"]);
default: throw MissingPluginException("notImplemented");
}
}
Future<Map<String, String>> _provideUserTokens(String userId) async {
// TOTO call your backend to fetch Nabla user tokens
String accessToken = "...";
String refreshToken = "...";
return {
"accessToken": accessToken,
"refreshToken": refreshToken,
};
}
Future<void> initialize(String apiKey) async {
try {
await _nablaChannel.invokeMethod('initialize', {'apiKey' : apiKey});
debugPrint('NablaNativeBridge.initialize successful');
} on PlatformException catch (e) {
debugPrint('Unable to initialize Nabla SDK: ${e.message}');
}
}
}
Updated 25 days ago