Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
When you integrate Dragon Copilot Embedded for Mobile with a React Native app, you need to write a middleware as a bridge between React Native and the SDK.
Part 1: Add dependencies
Open xcworkspace: From XCode IDE, open your React Native iOS project or workspace (*.xcworkspace). It might be available in the ios folder in your project.
Add the Dragon Copilot SPM as a package dependency: Open your React native iOS project settings, select Package Dependencies and enter the local path of the Dragon Copilot SPM.
Add the framework/library to the target: Open your app's target, select General, and add the DragonCopilotTurnkey xcframework.
Part 2: Write a bridge module
Create DRCBridgeModule.h and extend it from the
RCTEventEmitter
class. It should implement theRCTBridgeModule
protocol.In the DRCBridgeModule.h file, create the TurnkeyFramework object.
#ifndef DRCBridgeModule_h #define DRCBridgeModule_h #import <React/RCTBridgeModule.h> #import <React/RCTEventEmitter.h> #include <DragonCopilotTurnkey/DragonCopilotTurnkey.h> #import <DragonCopilotTurnkey/DragonCopilotTurnkey-Swift.h> @interface DRCBridgeModule : RCTEventEmitter <RCTBridgeModule> @property (nonatomic, strong) TurnkeyFramework *turnkeySdk; @end #endif /* DRCBridgeModule_h */
In DRCBridgeModule.m, add the following methods:
initTurnkeySdk
to start Dragon Copilot Embedded for Mobile. It should be called only once during the initialization.openSession
to display the Dragon Copilot UI on the screen. It should be called when a different session/encounter has selected.closeSession
to properly close an active patient session.dispose
to completely release all resources associated with theTurnkeyFramework
class when the user signs out.
// Start Dragon Copilot Embedded for Mobile RCT_EXPORT_METHOD(initTurnkeySdk) { dispatch_async(dispatch_get_main_queue(), ^{ self.turnkeySdk = [TurnkeyFramework initializeWithDataProvider:self delegate:self recordingDelegate:self dictationDelegate:self settingsDelegate:self]; }); } // Open a session RCT_EXPORT_METHOD(openSession) { dispatch_async(dispatch_get_main_queue(), ^{ UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController; NSObject *webViewContainer = [self.turnkeySdk openSessionControllerWithSessionDataProvider:self]; UIViewController *viewControllerToPresent = (UIViewController *) webViewContainer; [rootViewController presentViewController:viewControllerToPresent animated:YES completion:nil]; }); } // Close a session RCT_EXPORT_METHOD(closeSession) { dispatch_async(dispatch_get_main_queue(), ^{ if (self.turnkeySdk) { [self.turnkeySdk closeSession]; NSLog(@"Turnkey session closed."); } else { NSLog(@"Turnkey SDK is not initialized. Cannot close session."); } }); } // Dispose of the TurnkeyFramework class RCT_EXPORT_METHOD(disposeSdk) { dispatch_async(dispatch_get_main_queue(), ^{ if (self.turnkeySdk) { [TurnkeyFramework dispose]; self.turnkeySdk = nil; NSLog(@"Turnkey SDK disposed."); } else { NSLog(@"Turnkey SDK is not initialized. Cannot dispose."); } }); }
If required, implement
TDelegate
,TRecordingDelegate
,TDictationDelegate
, andTSettingDelegate
to receive callbacks from Dragon Copilot Embedded for Mobile.#pragma mark - TDelegate - (void)isTurnKeyWebViewLoaded:(BOOL)isLoadingDone { NSLog(@"[TDelegate] WebView loaded: %@", isLoadingDone ? @"YES" : @"NO"); } - (void)logoutWith:(LogoutReason)logoutType { NSString *reason = logoutType == LogoutReasonUser ? @"User" : @"Inactivity"; NSLog(@"[TDelegate] Logout occurred. Reason: %@", reason); } #pragma mark - TRecordingDelegate - (void)recordingStarted { NSLog(@"[TRecordingDelegate] Recording started"); } - (void)recordingFailed { NSLog(@"[TRecordingDelegate] Recording failed"); } - (void)recordingStopped { NSLog(@"[TRecordingDelegate] Recording stopped"); } - (void)recordingInterruptedWithReason:(RecordingInterruptionReason)reason { NSLog(@"[TRecordingDelegate] Recording interrupted. Reason: %ld", (long)reason); } - (void)recordingNotificationWithNotification:(RecordingNotification)notification { NSLog(@"[TRecordingDelegate] Recording notification. Notification: %ld", (long)notification); } #pragma mark - TDictationDelegate - (void)dictationStarted { NSLog(@"[TDictationDelegate] Dictation started"); } - (void)dictationStopped { NSLog(@"[TDictationDelegate] Dictation stopped"); } #pragma mark - TSettingsDelegate - (void)isIdleTimerDisabledIsOn:(BOOL)screenOn { NSLog(@"[TSettingsDelegate] Idle timer disabled: %@", screenOn ? @"YES" : @"NO"); } - (void)appearanceThemeChangedTo:(NSString *)uiTheme { NSLog(@"[TSettingsDelegate] Appearance theme changed to: %@", uiTheme); } - (void)changeApplicationLanguageTo:(NSString *)languageCode { NSLog(@"[TSettingsDelegate] Change application language to: %@", languageCode); }
Implement
TSessionDataProvider
,TConfigurationProvider
, andTAccessTokenProvider
protocols with implementation for the methods.@interface DRCBridgeModule () <TSessionDataProvider, TConfigurationProvider> @end - (TConfiguration * _Nonnull)getTConfiguration {} - (TUser * _Nonnull)getTUser {} - (TPatient * _Nonnull)getTPatient {} - (TVisit * _Nonnull)getTVisit {} - (id<TAccessTokenProvider> _Nonnull)getTAccessTokenProvider { return [[AuthProvider alloc] init]; }
Create AuthProvider.h for definitions and AuthProvider.m for implementation. Update the AuthProvider.m class to include your implementation for retrieving the JWT authentication token.
// AuthProvider.h #import <Foundation/Foundation.h> #import <DragonCopilotTurnkey/DragonCopilotTurnkey-Swift.h> NS_ASSUME_NONNULL_BEGIN @interface AuthProvider : NSObject <TAccessTokenProvider> /// Retrieves an access token for authentication. /// - Parameters: /// - scope: Optional array of scopes for token generation. /// - forceRefresh: When true, generate new token and provide /// - onSuccess: The callback that returns a TAuthResponse object if the token is successfully retrieved. /// - onFailure: The callback that returns an NSError object if token retrieval fails. - (void)accessTokenWithScope:(nullable NSArray<NSString *> *)scopes forceRefresh:(BOOL)forceRefresh onSuccess:(void (^)(TAuthResponse *authResponse))onSuccess onFailure:(void (^)(NSError *error))onFailure; @end NS_ASSUME_NONNULL_END // AuthProvider.m #import "AuthProvider.h" @implementation AuthProvider - (void)accessTokenWithScopes:(nullable NSArray<NSString *> *)scopes forceRefresh:(BOOL)forceRefresh onSuccess:(void (^)(TAuthResponse *authResponse))onSuccess onFailure:(void (^)(NSError *error))onFailure { // Example: Generate a sample token NSString *token = @"sampleJWTToken"; TTokenResponse *tokenResponse = [[TTokenResponse alloc] initWithToken:token]; TAuthResponse *authResponse = [[TAuthResponse alloc] initWithTokenResponse:tokenResponse]; // Call the success callback onSuccess(tokenResponse); } @end
Each of these methods is called synchronously from Dragon Copilot Embedded for Mobile when data is needed. You might need to have a mechanism to retrieve or construct data, for example using a semaphore, and provide information to the SDK.
Once a two-way synchronous communication channel has been successfully established between the Objective-C and JavaScript components of the React Native application, the next step is to perform a clean build of the iOS application and conduct testing.