Skip to content

Commit

Permalink
Merge branch 'react-native-webrtc-master'
Browse files Browse the repository at this point in the history
  • Loading branch information
tuanbm committed Dec 28, 2020
2 parents 650d447 + ba018f1 commit 7a8a4e0
Show file tree
Hide file tree
Showing 17 changed files with 728 additions and 274 deletions.
3 changes: 3 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
example/
node_modules/
.idea/
.github/
docs/
20 changes: 20 additions & 0 deletions MIGRATION_v3_v4.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Migration from CallKeep v3 to v4

The `reportNewIncomingCall` method on iOS is now more consistent.

Please update your `AppDelegate.m` file with this new signature:

```objc
[RNCallKeep reportNewIncomingCall: uuidString
handle: handle
handleType: handleType
hasVideo: YES
localizedCallerName: localizedCallerName
supportsHolding: YES
supportsDTMF: YES
supportsGrouping: YES
supportsUngrouping: YES
fromPushKit: YES
payload: nil
withCompletionHandler: nil];
```
155 changes: 151 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,14 @@ const options = {
cancelButton: 'Cancel',
okButton: 'ok',
imageName: 'phone_account_icon',
additionalPermissions: [PermissionsAndroid.PERMISSIONS.example]
additionalPermissions: [PermissionsAndroid.PERMISSIONS.example],
// Required to get audio in background when using Android 11
foregroundService: {
channelId: 'com.company.my',
channelName: 'Foreground service for my app',
notificationTitle: 'My app is running on background',
notificationIcon: 'Path to the resource icon of the notification',
},
}
};

Expand Down Expand Up @@ -86,6 +93,8 @@ RNCallKeep.setup(options).then(accepted => {});
- `additionalPermissions`: [PermissionsAndroid] (optional)
Any additional permissions you'd like your app to have at first launch. Can be used to simplify permission flows and avoid
multiple popups to the user at different times.

`setup` calls internally `registerPhoneAccount` and `registerEvents`.

## Constants

Expand Down Expand Up @@ -122,6 +131,30 @@ Eg: When your used log out (or the connection to your server is broken, etc..),
RNCallKeep.setAvailable(true);
```

### setForegroundServiceSettings
_This feature is available only on Android._

Configures the [Foreground Service](https://developer.android.com/about/versions/11/privacy/foreground-services) used for Android 11 to get microphone access on background.
Similar to set the `foregroundService` key in the `setup()` method.

```js
RNCallKeep.setForegroundServiceSettings({
channelId: 'com.company.my',
channelName: 'Foreground service for my app',
notificationTitle: 'My app is running on background',
notificationIcon: 'Path to the resource icon of the notification',
});
```

### canMakeMultipleCalls
_This feature is available only on Android._

Disable the "Add call" button in ConnectionService UI.

```js
RNCallKeep.canMakeMultipleCalls(false); // Enabled by default
```

- `active`: boolean
- Tell whether the app is ready or not

Expand Down Expand Up @@ -175,6 +208,13 @@ RNCallKeep.displayIncomingCall(uuid, handle, localizedCallerName);
- `hasVideo`: boolean (optional, iOS only)
- `false` (default)
- `true` (you know... when not false)
- `options`: object (optional)
- `ios`: object
- `supportsHolding`: boolean (optional, default true)
- `supportsDTMF`: boolean (optional, default true)
- `supportsGrouping`: boolean (optional, default true)
- `supportsUngrouping`: boolean (optional, default true)
- `android`: object (currently no-op)

### answerIncomingCall
_This feature is available only on Android._
Expand Down Expand Up @@ -230,6 +270,14 @@ RNCallKeep.updateDisplay(uuid, displayName, handle)
- Name of the caller to be displayed on the native UI
- `handle`: string
- Phone number of the caller
- `options`: object (optional)
- `ios`: object
- `hasVideo`: boolean (optional)
- `supportsHolding`: boolean (optional)
- `supportsDTMF`: boolean (optional)
- `supportsGrouping`: boolean (optional)
- `supportsUngrouping`: boolean (optional)
- `android`: object (currently no-op)

### endCall

Expand Down Expand Up @@ -386,6 +434,38 @@ const options = {
RNCallKeep.hasDefaultPhoneAccount(options);
```

### checkPhoneAccountEnabled

Checks if the user has set a default [phone account](https://developer.android.com/reference/android/telecom/PhoneAccount) and it's enabled.

It's useful for custom permission prompts. It should be used in pair with `registerPhoneAccount`
Similar to `hasDefaultPhoneAccount` but without trigering a prompt if the user doesn't have a phone account.

_This feature is available only on Android._

```js
RNCallKeep.checkPhoneAccountEnabled();
```

### isConnectionServiceAvailable

Check if the device support ConnectionService.

_This feature is available only on Android._

```js
RNCallKeep.checkPhoneAccountEnabled();
```

### backToForeground
_This feature is available only on Android._

Use this to display the application in foreground if the application was in background state.
This method will open the application if it was closed.

```js
RNCallKeep.backToForeground();
```

## Events

Expand Down Expand Up @@ -519,6 +599,31 @@ RNCallKeep.addEventListener('didPerformDTMFAction', ({ digits, callUUID }) => {
- `callUUID` (string)
- The UUID of the call.

### - didLoadWithEvents

iOS only.

Called as soon as JS context initializes if there were some actions performed by user before JS context has been created.

Since iOS 13, you must display incoming call on receiving PushKit push notification. But if app was killed, it takes some time to create JS context. If user answers the call (or ends it) before JS context has been initialized, user actions will be passed as events array of this event. Similar situation can happen if user would like to start a call from Recents or similar iOS app, assuming that your app was in killed state.

**NOTE: You still need to subscribe / handle the rest events as usuall. This is just a helper whcih cache and propagate early fired events if and only if for "the native events which DID fire BEFORE js bridge is initialed", it does NOT mean this will have events each time when the app reopened.**

```js
// register `didLoadWithEvents` somewhere early in your app when it is ready to handle callkeep events.

RNCallKeep.addEventListener('didLoadWithEvents', (events) => {
// `events` is passed as an Array chronologically, handle or ignore events based on the app's logic
// see example usage in https://github.com/react-native-webrtc/react-native-callkeep/pull/169 or https://github.com/react-native-webrtc/react-native-callkeep/pull/205
});
```

- `events` Array
- `name`: string
Native event name like: `RNCallKeepPerformAnswerCallAction`
- `data`: object
Object with data passed together with specific event so it can be handled in the same way like original event, for example `({ callUUID })` for `answerCall` event if `name` is `RNCallKeepPerformAnswerCallAction`

### - checkReachability

On Android when the application is in background, after a certain delay the OS will close every connection with informing about it.
Expand All @@ -538,6 +643,30 @@ Allows to remove the listener on an event.
RNCallKeep.removeEventListener('checkReachability');
```

### registerPhoneAccount

Registers Android phone account manually, useful for custom permission prompts when you don't want to call `setup()`.
This method is called by `setup`, if you already use setup you don't need it.

_This feature is available only on Android._
_On iOS you still have to call `setup()`._

```js
RNCallKeep.registerPhoneAccount();
```

### registerAndroidEvents

Registers Android UI events, useful when you don't want to call `setup()`.
This method is called by `setup`, if you already use setup you don't need it.

_This feature is available only on Android._
_On iOS you still have to call `setup()`._

```js
RNCallKeep.registerAndroidEvents();
```

## Example

A full example is available in the [example](https://github.com/react-native-webrtc/react-native-callkeep/tree/master/example) folder.
Expand Down Expand Up @@ -605,7 +734,7 @@ class RNCallKeepExample extends React.Component {

// Event Listener Callbacks

didReceiveStartCallAction(data) => {
didReceiveStartCallAction = (data) => {
let { handle, callUUID, name } = data;
// Get this event after the system decides you can start a call
// You can now start a call from within your app
Expand Down Expand Up @@ -669,7 +798,7 @@ In some case your application can be unreachable :
- when the user kill the application
- when it's in background since a long time (eg: after ~5mn the os will kill all connections).

To be able to wake up your application to display the incoming call, you can use [https://github.com/ianlin/react-native-voip-push-notification](react-native-voip-push-notification) on iOS or BackgroundMessaging from [react-native-firebase](https://rnfirebase.io/docs/v5.x.x/messaging/receiving-messages#4)-(Optional)(Android-only)-Listen-for-FCM-messages-in-the-background).
To be able to wake up your application to display the incoming call, you can use [https://github.com/ianlin/react-native-voip-push-notification](react-native-voip-push-notification) on iOS or BackgroundMessaging from [react-native-firebase](https://rnfirebase.io/messaging/usage#receiving-messages)-(Optional)(Android-only)-Listen-for-FCM-messages-in-the-background).

You have to send a push to your application, like with Firebase for Android and with a library supporting PushKit pushes for iOS.

Expand All @@ -688,10 +817,28 @@ Since iOS 13, you'll have to report the incoming calls that wakes up your applic
// NSString *handle = @"caller number here";
// NSDictionary *extra = [payload.dictionaryPayload valueForKeyPath:@"custom.path.to.data"]; /* use this to pass any special data (ie. from your notification) down to RN. Can also be `nil` */

[RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES payload:extra withCompletionHandler:completion];
[RNCallKeep reportNewIncomingCall: uuid
handle: handle
handleType: @"generic"
hasVideo: NO
localizedCallerName: callerName
supportsHolding: YES
supportsDTMF: YES
supportsGrouping: YES
supportsUngrouping: YES
fromPushKit: YES
payload: extra
withCompletionHandler: completion];
}
```

## Android 11

Since Android 11, your application [requires to start a foregroundService](https://developer.android.com/about/versions/11/privacy/foreground-services) in order to access the microphone in background.
You'll need to upgrade your `compileSdkVersion` to `30` to be able to use this feature.

You have to set the `foregroundService` key in the [`setup()`](#setup) method and add a `foregroundServiceType` in the [`AndroidManifest` file](docs/android-installation.md#android-common-step-installation).

## Debug

### Android
Expand Down
10 changes: 6 additions & 4 deletions actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const RNCallKeepDidToggleHoldAction = 'RNCallKeepDidToggleHoldAction';
const RNCallKeepDidPerformDTMFAction = 'RNCallKeepDidPerformDTMFAction';
const RNCallKeepProviderReset = 'RNCallKeepProviderReset';
const RNCallKeepCheckReachability = 'RNCallKeepCheckReachability';
const RNCallKeepShowIncomingCallUi = 'RNCallKeepShowIncomingCallUi';
const RNCallKeepDidLoadWithEvents = 'RNCallKeepDidLoadWithEvents';
const isIOS = Platform.OS === 'ios';

const didReceiveStartCallAction = handler => {
Expand Down Expand Up @@ -56,8 +56,10 @@ const didResetProvider = handler =>
const checkReachability = handler =>
eventEmitter.addListener(RNCallKeepCheckReachability, handler);

const showIncomingCallUi = handler =>
eventEmitter.addListener(RNCallKeepShowIncomingCallUi, (data) => handler(data));
const didLoadWithEvents = handler =>
eventEmitter.addListener(RNCallKeepDidLoadWithEvents, handler);

export const emit = (eventName, payload) => eventEmitter.emit(eventName, payload);

export const listeners = {
didReceiveStartCallAction,
Expand All @@ -71,5 +73,5 @@ export const listeners = {
didPerformDTMFAction,
didResetProvider,
checkReachability,
showIncomingCallUi
didLoadWithEvents,
};
3 changes: 1 addition & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@ def safeExtGet(prop, fallback) {
}

android {
compileSdkVersion safeExtGet('compileSdkVersion', 23)
buildToolsVersion safeExtGet('buildToolsVersion', "23.0.1")
compileSdkVersion safeExtGet('compileSdkVersion', 28)

defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 23)
Expand Down
6 changes: 3 additions & 3 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.wazo.callkeep">

<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
</manifest>
4 changes: 4 additions & 0 deletions android/src/main/java/io/wazo/callkeep/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,8 @@ public class Constants {
public static final String EXTRA_CALL_NUMBER = "EXTRA_CALL_NUMBER";
public static final String EXTRA_CALL_UUID = "EXTRA_CALL_UUID";
public static final String EXTRA_CALLER_NAME = "EXTRA_CALLER_NAME";
// Can't use telecom.EXTRA_DISABLE_ADD_CALL ...
public static final String EXTRA_DISABLE_ADD_CALL = "android.telecom.extra.DISABLE_ADD_CALL";

public static final int FOREGROUND_SERVICE_TYPE_MICROPHONE = 128;
}
Loading

0 comments on commit 7a8a4e0

Please sign in to comment.