omikit-plugin 4.1.0 → 4.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +449 -63
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/omikitplugin/OmiLocalCameraView.kt +21 -39
- package/android/src/main/java/com/omikitplugin/OmiRemoteCameraView.kt +40 -22
- package/android/src/main/java/com/omikitplugin/OmikitPluginModule.kt +28 -15
- package/android/src/main/java/com/omikitplugin/OmikitPluginPackage.kt +58 -22
- package/ios/Library/OmikitPlugin.swift +7 -7
- package/lib/commonjs/NativeOmikitPlugin.js.map +1 -1
- package/lib/commonjs/omikit.js +18 -0
- package/lib/commonjs/omikit.js.map +1 -1
- package/lib/module/NativeOmikitPlugin.js.map +1 -1
- package/lib/module/omikit.js +16 -0
- package/lib/module/omikit.js.map +1 -1
- package/omikit-plugin.podspec +32 -24
- package/package.json +1 -1
- package/src/NativeOmikitPlugin.ts +6 -0
- package/src/omikit.tsx +16 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The [omikit-plugin](https://www.npmjs.com/package/omikit-plugin) enables VoIP/SIP calling via the OMICALL platform with support for both Old and **New Architecture** (TurboModules + Fabric).
|
|
4
4
|
|
|
5
|
-
**Status:** Active maintenance | **Version:** 4.1.
|
|
5
|
+
**Status:** Active maintenance | **Version:** 4.1.1
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -46,7 +46,7 @@ The [omikit-plugin](https://www.npmjs.com/package/omikit-plugin) enables VoIP/SI
|
|
|
46
46
|
|
|
47
47
|
| Platform | SDK | Version |
|
|
48
48
|
|----------|-----|---------|
|
|
49
|
-
| Android | OMIKIT | 2.6.
|
|
49
|
+
| Android | OMIKIT | 2.6.6 |
|
|
50
50
|
| iOS | OmiKit | 1.11.4 |
|
|
51
51
|
|
|
52
52
|
### Platform Requirements
|
|
@@ -54,8 +54,8 @@ The [omikit-plugin](https://www.npmjs.com/package/omikit-plugin) enables VoIP/SI
|
|
|
54
54
|
| | Android | iOS |
|
|
55
55
|
|--|---------|-----|
|
|
56
56
|
| **Min SDK** | API 24 (Android 7.0) | iOS 13.0 |
|
|
57
|
-
| **Target SDK** | API
|
|
58
|
-
| **Compile SDK** | API
|
|
57
|
+
| **Target SDK** | API 36 (Android 16) | — |
|
|
58
|
+
| **Compile SDK** | API 36 | — |
|
|
59
59
|
|
|
60
60
|
### Device Requirements
|
|
61
61
|
|
|
@@ -131,7 +131,32 @@ Add to `android/app/src/main/AndroidManifest.xml`:
|
|
|
131
131
|
>
|
|
132
132
|
> Make sure to add the `tools` namespace to your manifest tag: `xmlns:tools="http://schemas.android.com/tools"`
|
|
133
133
|
|
|
134
|
-
### 2.
|
|
134
|
+
### 2. Incoming Call Activity (Required)
|
|
135
|
+
|
|
136
|
+
Your main Activity must handle incoming call intents from the SDK. Add the following `intent-filter` to your `MainActivity` in `AndroidManifest.xml`:
|
|
137
|
+
|
|
138
|
+
```xml
|
|
139
|
+
<activity
|
|
140
|
+
android:name=".MainActivity"
|
|
141
|
+
android:showWhenLocked="true"
|
|
142
|
+
android:turnScreenOn="true"
|
|
143
|
+
android:launchMode="singleTask"
|
|
144
|
+
...>
|
|
145
|
+
|
|
146
|
+
<!-- Incoming call intent-filter (required for lock screen) -->
|
|
147
|
+
<intent-filter>
|
|
148
|
+
<action android:name="${applicationId}.ACTION_INCOMING_CALL" />
|
|
149
|
+
<action android:name="android.intent.action.CALL" />
|
|
150
|
+
<category android:name="android.intent.category.DEFAULT" />
|
|
151
|
+
<data android:host="incoming_call" android:scheme="omisdk" />
|
|
152
|
+
</intent-filter>
|
|
153
|
+
</activity>
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
> **Important:** The `${applicationId}.ACTION_INCOMING_CALL` action ensures incoming calls show correctly on **lock screen** for Android 9-14. Without this, the default dialer may intercept the intent instead of your app.
|
|
157
|
+
|
|
158
|
+
### 3. Firebase Cloud Messaging (FCM)
|
|
159
|
+
|
|
135
160
|
|
|
136
161
|
Add your `google-services.json` to `android/app/`.
|
|
137
162
|
|
|
@@ -141,7 +166,7 @@ In `android/app/build.gradle`:
|
|
|
141
166
|
apply plugin: 'com.google.gms.google-services'
|
|
142
167
|
```
|
|
143
168
|
|
|
144
|
-
###
|
|
169
|
+
### 4. Maven Repository
|
|
145
170
|
|
|
146
171
|
**Option A — `settings.gradle.kts` (recommended for new projects)**
|
|
147
172
|
|
|
@@ -201,7 +226,7 @@ OMI_TOKEN=omi_github_access_token
|
|
|
201
226
|
|
|
202
227
|
> **Note:** Contact the OMICall development team to get `OMI_USER` and `OMI_TOKEN` credentials.
|
|
203
228
|
|
|
204
|
-
###
|
|
229
|
+
### 5. New Architecture (Optional)
|
|
205
230
|
|
|
206
231
|
To enable New Architecture on Android, in `android/gradle.properties`:
|
|
207
232
|
|
|
@@ -238,13 +263,352 @@ Enable **Push Notifications** capability in Xcode for VoIP push (PushKit).
|
|
|
238
263
|
|
|
239
264
|
### 4. AppDelegate Setup
|
|
240
265
|
|
|
241
|
-
|
|
266
|
+
The AppDelegate template differs depending on your React Native version. Choose the one that matches your project:
|
|
267
|
+
|
|
268
|
+
#### RN 0.74 – 0.78 (RCTAppDelegate pattern)
|
|
269
|
+
|
|
270
|
+
<details>
|
|
271
|
+
<summary>AppDelegate.h</summary>
|
|
242
272
|
|
|
243
273
|
```objc
|
|
244
|
-
#import <
|
|
245
|
-
#import <
|
|
274
|
+
#import <RCTAppDelegate.h>
|
|
275
|
+
#import <UIKit/UIKit.h>
|
|
276
|
+
#import <UserNotifications/UserNotifications.h>
|
|
277
|
+
#import <OmiKit/OmiKit.h>
|
|
278
|
+
|
|
279
|
+
@interface AppDelegate : RCTAppDelegate <UIApplicationDelegate, RCTBridgeDelegate, UNUserNotificationCenterDelegate>
|
|
280
|
+
|
|
281
|
+
@property (nonatomic, strong) UIWindow *window;
|
|
282
|
+
@property (nonatomic, strong) PushKitManager *pushkitManager;
|
|
283
|
+
@property (nonatomic, strong) CallKitProviderDelegate *provider;
|
|
284
|
+
@property (nonatomic, strong) PKPushRegistry *voipRegistry;
|
|
285
|
+
|
|
286
|
+
@end
|
|
246
287
|
```
|
|
247
288
|
|
|
289
|
+
</details>
|
|
290
|
+
|
|
291
|
+
<details>
|
|
292
|
+
<summary>AppDelegate.mm</summary>
|
|
293
|
+
|
|
294
|
+
```objc
|
|
295
|
+
#import "AppDelegate.h"
|
|
296
|
+
#import <Firebase.h>
|
|
297
|
+
#import <React/RCTBundleURLProvider.h>
|
|
298
|
+
#import <OmiKit/OmiKit.h>
|
|
299
|
+
|
|
300
|
+
#if __has_include("OmikitNotification.h")
|
|
301
|
+
#import "OmikitNotification.h"
|
|
302
|
+
#else
|
|
303
|
+
#import <omikit_plugin/OmikitNotification.h>
|
|
304
|
+
#endif
|
|
305
|
+
|
|
306
|
+
@implementation AppDelegate
|
|
307
|
+
|
|
308
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
309
|
+
{
|
|
310
|
+
self.moduleName = @"YourAppName"; // Replace with your app name
|
|
311
|
+
|
|
312
|
+
// ----- OmiKit Config ------
|
|
313
|
+
[OmiClient setEnviroment:KEY_OMI_APP_ENVIROMENT_SANDBOX
|
|
314
|
+
userNameKey:@"full_name"
|
|
315
|
+
maxCall:2
|
|
316
|
+
callKitImage:@"call_image"
|
|
317
|
+
typePushVoip:TYPE_PUSH_CALLKIT_DEFAULT];
|
|
318
|
+
|
|
319
|
+
self.provider = [[CallKitProviderDelegate alloc]
|
|
320
|
+
initWithCallManager:[OMISIPLib sharedInstance].callManager];
|
|
321
|
+
self.voipRegistry = [[PKPushRegistry alloc]
|
|
322
|
+
initWithQueue:dispatch_get_main_queue()];
|
|
323
|
+
self.pushkitManager = [[PushKitManager alloc]
|
|
324
|
+
initWithVoipRegistry:self.voipRegistry];
|
|
325
|
+
|
|
326
|
+
if (@available(iOS 10.0, *)) {
|
|
327
|
+
[UNUserNotificationCenter currentNotificationCenter].delegate =
|
|
328
|
+
(id<UNUserNotificationCenterDelegate>)self;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
if ([FIRApp defaultApp] == nil) {
|
|
332
|
+
[FIRApp configure];
|
|
333
|
+
}
|
|
334
|
+
// ----- End OmiKit Config ------
|
|
335
|
+
|
|
336
|
+
return [super application:application didFinishLaunchingWithOptions:launchOptions];
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Handle foreground notifications
|
|
340
|
+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
|
341
|
+
willPresentNotification:(UNNotification *)notification
|
|
342
|
+
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler
|
|
343
|
+
{
|
|
344
|
+
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Handle missed call notification tap
|
|
348
|
+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
|
349
|
+
didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|
350
|
+
withCompletionHandler:(void (^)())completionHandler
|
|
351
|
+
{
|
|
352
|
+
NSDictionary *userInfo = response.notification.request.content.userInfo;
|
|
353
|
+
if (userInfo && [userInfo valueForKey:@"omisdkCallerNumber"]) {
|
|
354
|
+
[OmikitNotification didRecieve:userInfo];
|
|
355
|
+
}
|
|
356
|
+
completionHandler();
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// Register push notification token
|
|
360
|
+
- (void)application:(UIApplication *)app
|
|
361
|
+
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken
|
|
362
|
+
{
|
|
363
|
+
const unsigned char *data = (const unsigned char *)[devToken bytes];
|
|
364
|
+
NSMutableString *token = [NSMutableString string];
|
|
365
|
+
for (NSUInteger i = 0; i < [devToken length]; i++) {
|
|
366
|
+
[token appendFormat:@"%02.2hhX", data[i]];
|
|
367
|
+
}
|
|
368
|
+
[OmiClient setUserPushNotificationToken:[token copy]];
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Terminate all calls when app is killed
|
|
372
|
+
- (void)applicationWillTerminate:(UIApplication *)application {
|
|
373
|
+
@try {
|
|
374
|
+
[OmiClient OMICloseCall];
|
|
375
|
+
} @catch (NSException *exception) {}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
|
379
|
+
{
|
|
380
|
+
return [self bundleURL];
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
- (NSURL *)bundleURL
|
|
384
|
+
{
|
|
385
|
+
#if DEBUG
|
|
386
|
+
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
|
387
|
+
#else
|
|
388
|
+
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
|
389
|
+
#endif
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
@end
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
</details>
|
|
396
|
+
|
|
397
|
+
#### RN 0.79+ (RCTReactNativeFactory pattern)
|
|
398
|
+
|
|
399
|
+
RN 0.79+ uses `RCTReactNativeFactory` instead of `RCTAppDelegate`. Add OmiKit setup in your existing AppDelegate:
|
|
400
|
+
|
|
401
|
+
<details>
|
|
402
|
+
<summary>AppDelegate.swift (Swift template)</summary>
|
|
403
|
+
|
|
404
|
+
```swift
|
|
405
|
+
import UIKit
|
|
406
|
+
import React
|
|
407
|
+
import ReactAppDependencyProvider
|
|
408
|
+
import OmiKit
|
|
409
|
+
|
|
410
|
+
@main
|
|
411
|
+
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
|
|
412
|
+
var window: UIWindow?
|
|
413
|
+
var provider: CallKitProviderDelegate?
|
|
414
|
+
var pushkitManager: PushKitManager?
|
|
415
|
+
var voipRegistry: PKPushRegistry?
|
|
416
|
+
|
|
417
|
+
func application(_ application: UIApplication,
|
|
418
|
+
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
419
|
+
// React Native setup
|
|
420
|
+
let delegate = ReactNativeDelegate()
|
|
421
|
+
let factory = RCTReactNativeFactory(delegate: delegate)
|
|
422
|
+
delegate.dependencyProvider = RCTAppDependencyProvider()
|
|
423
|
+
|
|
424
|
+
window = UIWindow(frame: UIScreen.main.bounds)
|
|
425
|
+
factory.startReactNative(
|
|
426
|
+
withModuleName: "YourAppName",
|
|
427
|
+
in: window,
|
|
428
|
+
launchOptions: launchOptions
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
// ----- OmiKit Config ------
|
|
432
|
+
#ifdef DEBUG
|
|
433
|
+
OmiClient.setEnviroment(KEY_OMI_APP_ENVIROMENT_SANDBOX,
|
|
434
|
+
userNameKey: "full_name",
|
|
435
|
+
maxCall: 1,
|
|
436
|
+
callKitImage: "call_image",
|
|
437
|
+
typePushVoip: TYPE_PUSH_CALLKIT_DEFAULT)
|
|
438
|
+
#else
|
|
439
|
+
OmiClient.setEnviroment(KEY_OMI_APP_ENVIROMENT_PRODUCTION,
|
|
440
|
+
userNameKey: "full_name",
|
|
441
|
+
maxCall: 1,
|
|
442
|
+
callKitImage: "call_image",
|
|
443
|
+
typePushVoip: TYPE_PUSH_CALLKIT_DEFAULT)
|
|
444
|
+
#endif
|
|
445
|
+
|
|
446
|
+
provider = CallKitProviderDelegate(callManager: OMISIPLib.sharedInstance().callManager)
|
|
447
|
+
voipRegistry = PKPushRegistry(queue: .main)
|
|
448
|
+
pushkitManager = PushKitManager(voipRegistry: voipRegistry!)
|
|
449
|
+
|
|
450
|
+
UNUserNotificationCenter.current().delegate = self
|
|
451
|
+
FirebaseApp.configure()
|
|
452
|
+
// ----- End OmiKit Config ------
|
|
453
|
+
|
|
454
|
+
return true
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Handle missed call notification tap
|
|
458
|
+
func userNotificationCenter(_ center: UNUserNotificationCenter,
|
|
459
|
+
didReceive response: UNNotificationResponse,
|
|
460
|
+
withCompletionHandler completionHandler: @escaping () -> Void) {
|
|
461
|
+
let userInfo = response.notification.request.content.userInfo
|
|
462
|
+
if userInfo["omisdkCallerNumber"] != nil {
|
|
463
|
+
OmikitNotification.didRecieve(userInfo)
|
|
464
|
+
}
|
|
465
|
+
completionHandler()
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Register push notification token
|
|
469
|
+
func application(_ application: UIApplication,
|
|
470
|
+
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
|
471
|
+
let token = deviceToken.map { String(format: "%02.2hhX", $0) }.joined()
|
|
472
|
+
OmiClient.setUserPushNotificationToken(token)
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Terminate all calls when app is killed
|
|
476
|
+
func applicationWillTerminate(_ application: UIApplication) {
|
|
477
|
+
try? OmiClient.omiCloseCall()
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
class ReactNativeDelegate: RCTDefaultReactNativeFactoryDelegate {
|
|
482
|
+
override func sourceURL(for bridge: RCTBridge) -> URL? {
|
|
483
|
+
return bundleURL()
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
override func bundleURL() -> URL? {
|
|
487
|
+
#if DEBUG
|
|
488
|
+
return RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index")
|
|
489
|
+
#else
|
|
490
|
+
return Bundle.main.url(forResource: "main", withExtension: "jsbundle")
|
|
491
|
+
#endif
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
</details>
|
|
497
|
+
|
|
498
|
+
<details>
|
|
499
|
+
<summary>AppDelegate.mm (Objective-C template)</summary>
|
|
500
|
+
|
|
501
|
+
```objc
|
|
502
|
+
#import "AppDelegate.h"
|
|
503
|
+
#import <Firebase.h>
|
|
504
|
+
#import <React/RCTBundleURLProvider.h>
|
|
505
|
+
#import <React/RCTReactNativeFactory.h>
|
|
506
|
+
#import <ReactAppDependencyProvider/RCTAppDependencyProvider.h>
|
|
507
|
+
#import <OmiKit/OmiKit.h>
|
|
508
|
+
|
|
509
|
+
#if __has_include("OmikitNotification.h")
|
|
510
|
+
#import "OmikitNotification.h"
|
|
511
|
+
#else
|
|
512
|
+
#import <omikit_plugin/OmikitNotification.h>
|
|
513
|
+
#endif
|
|
514
|
+
|
|
515
|
+
@interface ReactNativeDelegate : RCTDefaultReactNativeFactoryDelegate
|
|
516
|
+
@end
|
|
517
|
+
|
|
518
|
+
@implementation AppDelegate
|
|
519
|
+
|
|
520
|
+
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
521
|
+
{
|
|
522
|
+
ReactNativeDelegate *delegate = [ReactNativeDelegate new];
|
|
523
|
+
RCTReactNativeFactory *factory = [[RCTReactNativeFactory alloc] initWithDelegate:delegate];
|
|
524
|
+
delegate.dependencyProvider = [RCTAppDependencyProvider new];
|
|
525
|
+
|
|
526
|
+
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
|
|
527
|
+
[factory startReactNativeWithModuleName:@"YourAppName" in:self.window launchOptions:launchOptions];
|
|
528
|
+
|
|
529
|
+
// ----- OmiKit Config ------
|
|
530
|
+
#ifdef DEBUG
|
|
531
|
+
[OmiClient setEnviroment:KEY_OMI_APP_ENVIROMENT_SANDBOX userNameKey:@"full_name" maxCall:1 callKitImage:@"icYourApp" typePushVoip:@"background"];
|
|
532
|
+
#else
|
|
533
|
+
[OmiClient setEnviroment:KEY_OMI_APP_ENVIROMENT_PRODUCTION userNameKey:@"full_name" maxCall:1 callKitImage:@"icYourApp" typePushVoip:@"background"];
|
|
534
|
+
#endif
|
|
535
|
+
|
|
536
|
+
self.provider = [[CallKitProviderDelegate alloc]
|
|
537
|
+
initWithCallManager:[OMISIPLib sharedInstance].callManager];
|
|
538
|
+
self.voipRegistry = [[PKPushRegistry alloc]
|
|
539
|
+
initWithQueue:dispatch_get_main_queue()];
|
|
540
|
+
self.pushkitManager = [[PushKitManager alloc]
|
|
541
|
+
initWithVoipRegistry:self.voipRegistry];
|
|
542
|
+
|
|
543
|
+
if (@available(iOS 10.0, *)) {
|
|
544
|
+
[UNUserNotificationCenter currentNotificationCenter].delegate =
|
|
545
|
+
(id<UNUserNotificationCenterDelegate>)self;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if ([FIRApp defaultApp] == nil) {
|
|
549
|
+
[FIRApp configure];
|
|
550
|
+
}
|
|
551
|
+
// ----- End OmiKit Config ------
|
|
552
|
+
|
|
553
|
+
return YES;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
// Handle missed call notification tap
|
|
557
|
+
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
|
|
558
|
+
didReceiveNotificationResponse:(UNNotificationResponse *)response
|
|
559
|
+
withCompletionHandler:(void (^)())completionHandler
|
|
560
|
+
{
|
|
561
|
+
NSDictionary *userInfo = response.notification.request.content.userInfo;
|
|
562
|
+
if (userInfo && [userInfo valueForKey:@"omisdkCallerNumber"]) {
|
|
563
|
+
[OmikitNotification didRecieve:userInfo];
|
|
564
|
+
}
|
|
565
|
+
completionHandler();
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
// Register push notification token
|
|
569
|
+
- (void)application:(UIApplication *)app
|
|
570
|
+
didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)devToken
|
|
571
|
+
{
|
|
572
|
+
const unsigned char *data = (const unsigned char *)[devToken bytes];
|
|
573
|
+
NSMutableString *token = [NSMutableString string];
|
|
574
|
+
for (NSUInteger i = 0; i < [devToken length]; i++) {
|
|
575
|
+
[token appendFormat:@"%02.2hhX", data[i]];
|
|
576
|
+
}
|
|
577
|
+
[OmiClient setUserPushNotificationToken:[token copy]];
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Terminate all calls when app is killed
|
|
581
|
+
- (void)applicationWillTerminate:(UIApplication *)application {
|
|
582
|
+
@try {
|
|
583
|
+
[OmiClient OMICloseCall];
|
|
584
|
+
} @catch (NSException *exception) {}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
@end
|
|
588
|
+
|
|
589
|
+
@implementation ReactNativeDelegate
|
|
590
|
+
|
|
591
|
+
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
|
|
592
|
+
{
|
|
593
|
+
return [self bundleURL];
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
- (NSURL *)bundleURL
|
|
597
|
+
{
|
|
598
|
+
#if DEBUG
|
|
599
|
+
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
|
|
600
|
+
#else
|
|
601
|
+
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
|
|
602
|
+
#endif
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
@end
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
</details>
|
|
609
|
+
|
|
610
|
+
> **Note:** Replace `YourAppName` with your app's module name. For production, change `KEY_OMI_APP_ENVIROMENT_SANDBOX` to `KEY_OMI_APP_ENVIROMENT_PRODUCTION`.
|
|
611
|
+
|
|
248
612
|
### 5. New Architecture (Optional)
|
|
249
613
|
|
|
250
614
|
In your `Podfile`:
|
|
@@ -253,15 +617,20 @@ In your `Podfile`:
|
|
|
253
617
|
ENV['RN_NEW_ARCH_ENABLED'] = '1'
|
|
254
618
|
```
|
|
255
619
|
|
|
256
|
-
For **
|
|
620
|
+
For **New Architecture with video call support**, add Fabric interop registration in `AppDelegate.mm` inside `didFinishLaunchingWithOptions`, **before** `return [super ...]`:
|
|
257
621
|
|
|
258
622
|
```objc
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
623
|
+
// Required imports at the top of AppDelegate.mm
|
|
624
|
+
#import <React-RCTFabric/React/RCTComponentViewFactory.h>
|
|
625
|
+
#import <React-RCTFabric/React/RCTLegacyViewManagerInteropComponentView.h>
|
|
626
|
+
|
|
627
|
+
// Inside didFinishLaunchingWithOptions, before return:
|
|
628
|
+
[RCTLegacyViewManagerInteropComponentView supportLegacyViewManagerWithName:@"OmiLocalCameraView"];
|
|
629
|
+
[RCTLegacyViewManagerInteropComponentView supportLegacyViewManagerWithName:@"OmiRemoteCameraView"];
|
|
263
630
|
```
|
|
264
631
|
|
|
632
|
+
> **Important:** Bridgeless mode is **not yet supported** for video call views. If you use New Architecture, keep bridge mode enabled (do **not** add `bridgelessEnabled` returning `YES`).
|
|
633
|
+
|
|
265
634
|
Then run `cd ios && pod install`.
|
|
266
635
|
|
|
267
636
|
---
|
|
@@ -293,7 +662,7 @@ Then run `cd ios && pod install`.
|
|
|
293
662
|
│ │ │ │ │ │
|
|
294
663
|
│ ▼ │ │ ▼ │
|
|
295
664
|
│ OMIKIT SDK │ │ OmiKit SDK │
|
|
296
|
-
│ (v2.6.
|
|
665
|
+
│ (v2.6.5) │ │ (v1.11.4) │
|
|
297
666
|
│ │ │ │ │ │
|
|
298
667
|
│ ▼ │ │ ▼ │
|
|
299
668
|
│ SIP Stack │ │ SIP Stack │
|
|
@@ -1270,73 +1639,90 @@ PBX ──► FCM ──► App receives data message
|
|
|
1270
1639
|
- Foreground service keeps the app alive during the call
|
|
1271
1640
|
- Full-screen intent for lock screen call UI
|
|
1272
1641
|
|
|
1273
|
-
|
|
1642
|
+
---
|
|
1274
1643
|
|
|
1275
|
-
|
|
1276
|
-
// Hide the system notification without affecting SIP registration
|
|
1277
|
-
await hideSystemNotificationSafely();
|
|
1644
|
+
## Permissions
|
|
1278
1645
|
|
|
1279
|
-
|
|
1280
|
-
await hideSystemNotificationOnly();
|
|
1646
|
+
Runtime permissions must be granted before making or receiving calls. We recommend using [`react-native-permissions`](https://github.com/zoontek/react-native-permissions) for a consistent cross-platform experience.
|
|
1281
1647
|
|
|
1282
|
-
|
|
1283
|
-
|
|
1648
|
+
### Install
|
|
1649
|
+
|
|
1650
|
+
```bash
|
|
1651
|
+
npm install react-native-permissions
|
|
1652
|
+
# iOS
|
|
1653
|
+
cd ios && pod install
|
|
1284
1654
|
```
|
|
1285
1655
|
|
|
1286
|
-
|
|
1656
|
+
### Android Runtime Permissions
|
|
1657
|
+
|
|
1658
|
+
```typescript
|
|
1659
|
+
import { check, request, PERMISSIONS, RESULTS, Platform } from 'react-native-permissions';
|
|
1287
1660
|
|
|
1288
|
-
|
|
1661
|
+
async function requestCallPermissions(isVideo: boolean) {
|
|
1662
|
+
if (Platform.OS !== 'android') return true;
|
|
1289
1663
|
|
|
1290
|
-
|
|
1664
|
+
// Voice call permissions
|
|
1665
|
+
const permissions = [
|
|
1666
|
+
PERMISSIONS.ANDROID.RECORD_AUDIO,
|
|
1667
|
+
PERMISSIONS.ANDROID.CALL_PHONE,
|
|
1668
|
+
PERMISSIONS.ANDROID.POST_NOTIFICATIONS, // Android 13+
|
|
1669
|
+
];
|
|
1670
|
+
|
|
1671
|
+
// Video call — add camera
|
|
1672
|
+
if (isVideo) {
|
|
1673
|
+
permissions.push(PERMISSIONS.ANDROID.CAMERA);
|
|
1674
|
+
}
|
|
1675
|
+
|
|
1676
|
+
const results = await Promise.all(permissions.map((p) => request(p)));
|
|
1677
|
+
return results.every((r) => r === RESULTS.GRANTED);
|
|
1678
|
+
}
|
|
1679
|
+
```
|
|
1291
1680
|
|
|
1292
|
-
###
|
|
1681
|
+
### iOS Runtime Permissions
|
|
1293
1682
|
|
|
1294
1683
|
```typescript
|
|
1295
|
-
import {
|
|
1296
|
-
checkAndRequestPermissions,
|
|
1297
|
-
checkPermissionStatus,
|
|
1298
|
-
requestPermissionsByCodes,
|
|
1299
|
-
requestSystemAlertWindowPermission,
|
|
1300
|
-
openSystemAlertSetting,
|
|
1301
|
-
} from 'omikit-plugin';
|
|
1684
|
+
import { request, PERMISSIONS, RESULTS, Platform } from 'react-native-permissions';
|
|
1302
1685
|
|
|
1303
|
-
|
|
1304
|
-
|
|
1686
|
+
async function requestCallPermissions(isVideo: boolean) {
|
|
1687
|
+
if (Platform.OS !== 'ios') return true;
|
|
1305
1688
|
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1689
|
+
const micResult = await request(PERMISSIONS.IOS.MICROPHONE);
|
|
1690
|
+
if (micResult !== RESULTS.GRANTED) return false;
|
|
1691
|
+
|
|
1692
|
+
if (isVideo) {
|
|
1693
|
+
const camResult = await request(PERMISSIONS.IOS.CAMERA);
|
|
1694
|
+
if (camResult !== RESULTS.GRANTED) return false;
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
return true;
|
|
1698
|
+
}
|
|
1309
1699
|
```
|
|
1310
1700
|
|
|
1311
|
-
###
|
|
1701
|
+
### Overlay Permission (Android only)
|
|
1702
|
+
|
|
1703
|
+
To show incoming call UI on lock screen, overlay permission is required:
|
|
1312
1704
|
|
|
1313
1705
|
```typescript
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
await requestPermissionsByCodes([451]);
|
|
1322
|
-
break;
|
|
1323
|
-
case 452: // OmiStartCallStatus.permissionOverlay
|
|
1324
|
-
await requestSystemAlertWindowPermission();
|
|
1325
|
-
// or open system settings directly:
|
|
1326
|
-
await openSystemAlertSetting();
|
|
1327
|
-
break;
|
|
1328
|
-
}
|
|
1706
|
+
import { requestSystemAlertWindowPermission, openSystemAlertSetting } from 'omikit-plugin';
|
|
1707
|
+
|
|
1708
|
+
// Request overlay permission
|
|
1709
|
+
await requestSystemAlertWindowPermission();
|
|
1710
|
+
|
|
1711
|
+
// Or open system settings directly
|
|
1712
|
+
await openSystemAlertSetting();
|
|
1329
1713
|
```
|
|
1330
1714
|
|
|
1331
|
-
### Permission
|
|
1715
|
+
### Permission Summary
|
|
1332
1716
|
|
|
1333
|
-
|
|
|
1334
|
-
|
|
1335
|
-
|
|
|
1336
|
-
|
|
|
1337
|
-
|
|
|
1717
|
+
| Permission | Platform | Required for |
|
|
1718
|
+
|-----------|----------|--------------|
|
|
1719
|
+
| Microphone (`RECORD_AUDIO`) | Android & iOS | All calls |
|
|
1720
|
+
| Camera (`CAMERA`) | Android & iOS | Video calls only |
|
|
1721
|
+
| Phone (`CALL_PHONE`) | Android | VoIP calls |
|
|
1722
|
+
| Notification (`POST_NOTIFICATIONS`) | Android 13+ | Incoming call notifications |
|
|
1723
|
+
| Overlay (`SYSTEM_ALERT_WINDOW`) | Android | Incoming call popup on lock screen |
|
|
1338
1724
|
|
|
1339
|
-
> **Note:** On iOS, permissions are handled via `Info.plist` and system prompts.
|
|
1725
|
+
> **Note:** On iOS, microphone and camera permissions are handled via `Info.plist` descriptions and system prompts. Overlay permission is not applicable on iOS.
|
|
1340
1726
|
|
|
1341
1727
|
---
|
|
1342
1728
|
|
package/android/build.gradle
CHANGED
|
@@ -65,7 +65,7 @@ dependencies {
|
|
|
65
65
|
// OMISDK
|
|
66
66
|
implementation("androidx.work:work-runtime:2.8.1")
|
|
67
67
|
implementation "androidx.security:security-crypto:1.1.0-alpha06"
|
|
68
|
-
api "io.omicrm.vihat:omi-sdk:2.6.
|
|
68
|
+
api "io.omicrm.vihat:omi-sdk:2.6.8"
|
|
69
69
|
|
|
70
70
|
// React Native — resolved from consumer's node_modules
|
|
71
71
|
implementation "com.facebook.react:react-native:+"
|