Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented expo plugin #111

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@

# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
Expand Down
158 changes: 100 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ React Native VoIP Push Notification - Currently iOS >= 8.0 only

## RN Version

* 1.1.0+ ( RN 40+ )
* 2.0.0+ (RN 60+)
- 1.1.0+ ( RN 40+ )
- 2.0.0+ (RN 60+)

## !!IMPORTANT NOTE!!

Expand All @@ -23,42 +23,42 @@ https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784
> When linking against the iOS 13 SDK or later, your implementation of this method must report notifications of type voIP to the CallKit framework by calling the reportNewIncomingCall(with:update:completion:) method
>
> On iOS 13.0 and later, if you fail to report a call to CallKit, the system will terminate your app.
>
>
> Repeatedly failing to report calls may cause the system to stop delivering any more VoIP push notifications to your app.
>
>
> If you want to initiate a VoIP call without using CallKit, register for push notifications using the UserNotifications framework instead of PushKit. For more information, see UserNotifications.

#### Issue introduced in this change:

When received VoipPush, we should present CallKit ASAP even before RN instance initialization.
This breaks especially if you handled almost call behavior at js side, for example:
Do-Not-Disturb / check if Ghost-Call / using some sip libs to register or waiting invite...etc.
When received VoipPush, we should present CallKit ASAP even before RN instance initialization.

This breaks especially if you handled almost call behavior at js side, for example:
Do-Not-Disturb / check if Ghost-Call / using some sip libs to register or waiting invite...etc.

Staff from Apple gives some advisions for these issues in the below discussion:
https://forums.developer.apple.com/thread/117939

#### You may need to change your server for APN voip push:

Especially `apns-push-type` value should be `'voip'` for iOS 13
And be aware of `apns-expiration`value, adjust according to your call logics
Especially `apns-push-type` value should be `'voip'` for iOS 13
And be aware of `apns-expiration`value, adjust according to your call logics

https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns

#### About Silent Push ( Background Push ):

VoIP pushes were intended to specifically support incoming call notifications and nothing else.
VoIP pushes were intended to specifically support incoming call notifications and nothing else.

If you were using voip push to do things other than `nootify incoming call`, such as: `cancel call` / `background updates`...etc, You should change to use [Notification Service Extension](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension), it contains different kind of pushs.
If you were using voip push to do things other than `nootify incoming call`, such as: `cancel call` / `background updates`...etc, You should change to use [Notification Service Extension](https://developer.apple.com/documentation/usernotifications/unnotificationserviceextension), it contains different kind of pushs.

To use`Background Push` to [Pushing Background Updates to Your App](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app),
To use`Background Push` to [Pushing Background Updates to Your App](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_background_updates_to_your_app),
You should:

1. Make sure you enabled `Xcode` -> `Signing & Capabilities` -> `Background Modes` -> `Remote Notifications` enabled
2. When sending background push from your APN back-end, the push header / payload should set:
* content-available = 1
* apns-push-type = 'background'
* apns-priority = 5

- content-available = 1
- apns-push-type = 'background'
- apns-priority = 5

## Installation

Expand All @@ -75,8 +75,9 @@ The iOS version should be >= 8.0 since we are using [PushKit][1].
Please refer to [VoIP Best Practices][2].

Make sure you enabled the folowing in `Xcode` -> `Signing & Capabilities`:
* `Background Modes` -> `Voice over IP` enabled
* `+Capability` -> `Push Notifications`

- `Background Modes` -> `Voice over IP` enabled
- `+Capability` -> `Push Notifications`

#### AppDelegate.m Modification

Expand All @@ -94,7 +95,7 @@ Make sure you enabled the folowing in `Xcode` -> `Signing & Capabilities`:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];



// ===== (THIS IS OPTIONAL BUT RECOMMENDED) =====
Expand Down Expand Up @@ -125,7 +126,7 @@ Make sure you enabled the folowing in `Xcode` -> `Signing & Capabilities`:

// --- Handle incoming pushes
- (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion {


// --- NOTE: apple forced us to invoke callkit ASAP when we receive voip push
// --- see: react-native-callkeep
Expand All @@ -143,7 +144,7 @@ Make sure you enabled the folowing in `Xcode` -> `Signing & Capabilities`:

// --- You should make sure to report to callkit BEFORE execute `completion()`
[RNCallKeep reportNewIncomingCall:uuid handle:handle handleType:@"generic" hasVideo:false localizedCallerName:callerName fromPushKit: YES payload:nil];

// --- You don't need to call it if you stored `completion()` and will call it on the js side.
completion();
}
Expand All @@ -153,34 +154,75 @@ Make sure you enabled the folowing in `Xcode` -> `Signing & Capabilities`:

```

### EXPO:

The following VOIP json properties are required and prevent crashing your app:

```typescript
{
uuid: string;
callerName: string;
handle: string;
isVideo: boolean; //optional; default to false
// rest of your data
}
```

It is important to install this with react-native-callkeep, so you can use the CallKit to present the incoming call screen.
Make sure you set the following in your `app.json`:

```javascript
{
"expo": {
"ios": {
"infoPlist": {
"UIBackgroundModes": [
"remote-notification", //for background notification optional
"voip" // permission for voip
]
}
},
"plugins": [
..., // other plugins
"react-native-voip-push-notification"
]
}
}
```

## Linking:

On RN60+, auto linking with pod file should work.
On RN60+, auto linking with pod file should work.

<details>
<summary>Linking Manually</summary>

### Add PushKit Framework:

- In your Xcode project, select `Build Phases` --> `Link Binary With Libraries`
- Add `PushKit.framework`

### Add RNVoipPushNotification:

#### Option 1: Use [rnpm][3]

```bash
rnpm link react-native-voip-push-notification
```

**Note**: If you're using rnpm link make sure the `Header Search Paths` is `recursive`. (In step 3 of manually linking)

#### Option 2: Manually

1. Drag `node_modules/react-native-voip-push-notification/ios/RNVoipPushNotification.xcodeproj` under `<your_xcode_project>/Libraries`
2. Select `<your_xcode_project>` --> `Build Phases` --> `Link Binary With Libraries`
- Drag `Libraries/RNVoipPushNotification.xcodeproj/Products/libRNVoipPushNotification.a` to `Link Binary With Libraries`
3. Select `<your_xcode_project>` --> `Build Settings`
- In `Header Search Paths`, add `$(SRCROOT)/../node_modules/react-native-voip-push-notification/ios/RNVoipPushNotification` with `recursive`
### Add PushKit Framework:

- In your Xcode project, select `Build Phases` --> `Link Binary With Libraries`
- Add `PushKit.framework`

### Add RNVoipPushNotification:

#### Option 1: Use [rnpm][3]

```bash
rnpm link react-native-voip-push-notification
```

**Note**: If you're using rnpm link make sure the `Header Search Paths` is `recursive`. (In step 3 of manually linking)

#### Option 2: Manually

1. Drag `node_modules/react-native-voip-push-notification/ios/RNVoipPushNotification.xcodeproj` under `<your_xcode_project>/Libraries`
2. Select `<your_xcode_project>` --> `Build Phases` --> `Link Binary With Libraries`

- Drag `Libraries/RNVoipPushNotification.xcodeproj/Products/libRNVoipPushNotification.a` to `Link Binary With Libraries`

3. Select `<your_xcode_project>` --> `Build Settings`

- In `Header Search Paths`, add `$(SRCROOT)/../node_modules/react-native-voip-push-notification/ios/RNVoipPushNotification` with `recursive`

</details>

## API and Usage:
Expand All @@ -190,27 +232,27 @@ On RN60+, auto linking with pod file should work.
Voip Push is time sensitive, these native API mainly used in AppDelegate.m, especially before JS bridge is up.
This usually

* `(void)voipRegistration` ---
- `(void)voipRegistration` ---
register delegate for PushKit if you like to register in AppDelegate.m ASAP instead JS side ( too late for some use cases )
* `(void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type` ---
- `(void)didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(NSString *)type` ---
call this api to fire 'register' event to JS
* `(void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type` ---
- `(void)didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(NSString *)type` ---
call this api to fire 'notification' event to JS
* `(void)addCompletionHandler:(NSString *)uuid completionHandler:(RNVoipPushNotificationCompletion)completionHandler` ---
- `(void)addCompletionHandler:(NSString *)uuid completionHandler:(RNVoipPushNotificationCompletion)completionHandler` ---
add completionHandler to RNVoipPush module
* `(void)removeCompletionHandler:(NSString *)uuid` ---
- `(void)removeCompletionHandler:(NSString *)uuid` ---
remove completionHandler to RNVoipPush module

#### JS API:

* `registerVoipToken()` --- JS method to register PushKit delegate
* `onVoipNotificationCompleted(notification.uuid)` --- JS mehtod to tell PushKit we have handled received voip push
- `registerVoipToken()` --- JS method to register PushKit delegate
- `onVoipNotificationCompleted(notification.uuid)` --- JS mehtod to tell PushKit we have handled received voip push

#### Events:

* `'register'` --- fired when PushKit give us the latest token
* `'notification'` --- fired when received voip push notification
* `'didLoadWithEvents'` --- fired when there are not-fired events been cached before js bridge is up
- `'register'` --- fired when PushKit give us the latest token
- `'notification'` --- fired when received voip push notification
- `'didLoadWithEvents'` --- fired when there are not-fired events been cached before js bridge is up

```javascript

Expand Down Expand Up @@ -245,7 +287,7 @@ class MyComponent extends React.Component {
VoipPushNotification.addEventListener('notification', (notification) => {
// --- when receive remote voip push, register your VoIP client, show local notification ... etc
this.doSomething();

// --- optionally, if you `addCompletionHandler` from the native side, once you have done the js jobs to initiate a call, call `completion()`
VoipPushNotification.onVoipNotificationCompleted(notification.uuid);
});
Expand Down
1 change: 1 addition & 0 deletions app.plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("./plugin/build");
Loading