Skip to content

Commit 395aaa3

Browse files
authored
feature: added some doc (#86)
* feature: added some doc [WIP] * feature: added more doc * feature: added more doc * feature: added more doc on README.md * feature: added more doc on README.md * feature: doc added * feature: doc added * feature: doc added * feature: doc added
1 parent 276f73f commit 395aaa3

File tree

2 files changed

+200
-4
lines changed

2 files changed

+200
-4
lines changed

README.md

Lines changed: 200 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,214 @@
55
* iOS CallKit and Android ConnectionService for Flutter
66
* Support FCM and PushKit
77

8-
## push payload
8+
> Keep in mind Callkit is banned in China, so if you want your app in the chinese AppStore consider include a basic alternative for notifying calls (ex. FCM notifications with sound).
9+
10+
`* P-C-M means -> presenter / controller / manager`
11+
12+
## Introduction
13+
14+
Callkeep acts as an intermediate between your call system (RTC, VOIP...) and the user, offering a native calling interface for handling your app calls.
15+
16+
This allows you (for example) to answer calls when your device is locked even if your app is terminated.
17+
18+
19+
## Initial setup
20+
21+
Basic configuration. In Android a popup is displayed before starting requesting some permissions to work properly.
22+
23+
```dart
24+
final callSetup = <String, dynamic>{
25+
'ios': {
26+
'appName': 'CallKeepDemo',
27+
},
28+
'android': {
29+
'alertTitle': 'Permissions required',
30+
'alertDescription':
31+
'This application needs to access your phone accounts',
32+
'cancelButton': 'Cancel',
33+
'okButton': 'ok',
34+
},
35+
};
36+
37+
callKeep.setup(callSetup);
38+
```
39+
40+
This configuration should be defined when your application wakes up, but keep in mind this alert will appear if you aren't granting the needed permissions yet.
41+
42+
A clean alternative is to control by yourself the required permissions when your application wakes up, and only invoke the `setup()` method if those permissions are granted.
43+
44+
## Events
45+
46+
Callkeep offers some events to handle native actions during a call.
47+
48+
These events are quite crucial because they act as an intermediate between the native calling UI and your call P-C-M.
49+
50+
What does it mean?
51+
52+
Assuming your application already implements some calling system (RTC, Voip, or whatever) with its own calling UI, you are using some basic controls:
53+
54+
<img width="40%" vspace="10" src="https://raw.githubusercontent.com/efraespada/callkeep/master/images/sample.png"></p>
55+
56+
> before implementing `callkeep`
57+
58+
- Hang up -> `presenter.hangUp()`
59+
- Microphone switcher -> `presenter.microSwitch()`
60+
61+
> after implementing `callkeep`
62+
63+
- Hang up -> `callkeep.endCall(call_uuid)`
64+
- Microphone switcher -> `callKeep.setMutedCall(uuid, true / false)`
65+
66+
Then you handle the action:
67+
68+
```dart
69+
Function(CallKeepPerformAnswerCallAction) answerAction = (event) async {
70+
print('CallKeepPerformAnswerCallAction ${event.callUUID}');
71+
// notify to your call P-C-M the answer action
72+
};
73+
74+
Function(CallKeepPerformEndCallAction) endAction = (event) async {
75+
print('CallKeepPerformEndCallAction ${event.callUUID}');
76+
// notify to your call P-C-M the end action
77+
};
78+
79+
Function(CallKeepDidPerformSetMutedCallAction) setMuted = (event) async {
80+
print('CallKeepDidPerformSetMutedCallAction ${event.callUUID}');
81+
// notify to your call P-C-M the muted switch action
82+
};
83+
84+
Function(CallKeepDidToggleHoldAction) onHold = (event) async {
85+
print('CallKeepDidToggleHoldAction ${event.callUUID}');
86+
// notify to your call P-C-M the hold switch action
87+
};
88+
```
89+
90+
```dart
91+
callKeep.on(CallKeepDidToggleHoldAction(), onHold);
92+
callKeep.on(CallKeepPerformAnswerCallAction(), answerAction);
93+
callKeep.on(CallKeepPerformEndCallAction(), endAction);
94+
callKeep.on(CallKeepDidPerformSetMutedCallAction(), setMuted);
95+
```
96+
97+
## Display incoming calls in foreground, background or terminate state
98+
99+
The incoming call concept we are looking for is firing an incoming call action when "something" is received in our app.
100+
101+
I've tested this concept with FCM and it works pretty fine.
102+
103+
```dart
104+
final FlutterCallkeep _callKeep = FlutterCallkeep();
105+
bool _callKeepStarted = false;
106+
107+
Future<void> _firebaseMessagingBackgroundHandler(RemoteMessage message) async {
108+
await Firebase.initializeApp();
109+
if (!_callKeepStarted) {
110+
try {
111+
await _callKeep.setup(callSetup);
112+
_callKeepStarted = true;
113+
} catch (e) {
114+
print(e);
115+
}
116+
}
117+
118+
// then process your remote message looking for some call uuid
119+
// and display any incoming call
120+
}
121+
```
122+
123+
Displaying incoming calls is really simple if you are receiving FCM messages (or whatever). This example shows how to show and close any incoming call:
124+
125+
> Notice that getting data from the payload can be done as you want, this is an example.
126+
127+
A payload data example:
9128

10129
```json
11130
{
12131
"uuid": "xxxxx-xxxxx-xxxxx-xxxxx",
13-
"caller_id": "+8618612345678",
14-
"caller_name": "hello",
132+
"caller_id": "+0123456789",
133+
"caller_name": "Draco",
15134
"caller_id_type": "number",
16-
"has_video": false,
135+
"has_video": "false"
17136
}
18137
```
19138

139+
A `RemoteMessage` extension for getting data:
140+
141+
```dart
142+
import 'dart:convert';
143+
144+
import 'package:firebase_messaging/firebase_messaging.dart';
145+
146+
extension RemoteMessageExt on RemoteMessage {
147+
Map<String, dynamic> getContent() {
148+
return jsonDecode(this.data["content"]);
149+
}
150+
151+
Map<String, dynamic> payload() {
152+
return getContent()["payload"];
153+
}
154+
}
155+
```
156+
157+
Methods to show and close incoming calls:
158+
159+
```dart
160+
Future<void> showIncomingCall(
161+
BuildContext context,
162+
RemoteMessage remoteMessage,
163+
FlutterCallkeep callKeep,
164+
) async {
165+
var callerIdFrom = remoteMessage.payload()["caller_id"] as String;
166+
var callerName = remoteMessage.payload()["caller_name"] as String;
167+
var uuid = remoteMessage.payload()["uuid"] as String;
168+
var hasVideo = remoteMessage.payload()["has_video"] == "true";
169+
170+
callKeep.on(CallKeepDidToggleHoldAction(), onHold);
171+
callKeep.on(CallKeepPerformAnswerCallAction(), answerAction);
172+
callKeep.on(CallKeepPerformEndCallAction(), endAction);
173+
callKeep.on(CallKeepDidPerformSetMutedCallAction(), setMuted);
174+
175+
print('backgroundMessage: displayIncomingCall ($uuid)');
176+
177+
bool hasPhoneAccount = await callKeep.hasPhoneAccount();
178+
if (!hasPhoneAccount) {
179+
hasPhoneAccount = await callKeep.hasDefaultPhoneAccount(context, callSetup["android"]);
180+
}
181+
182+
if (!hasPhoneAccount) {
183+
return;
184+
}
185+
186+
await callKeep.displayIncomingCall(uuid, callerIdFrom, localizedCallerName: callerName, hasVideo: hasVideo);
187+
callKeep.backToForeground();
188+
}
189+
190+
Future<void> closeIncomingCall(
191+
RemoteMessage remoteMessage,
192+
FlutterCallkeep callKeep,
193+
) async {
194+
var uuid = remoteMessage.payload()[MessageManager.CALLER_UUID] as String;
195+
print('backgroundMessage: closeIncomingCall ($uuid)');
196+
bool hasPhoneAccount = await callKeep.hasPhoneAccount();
197+
if (!hasPhoneAccount) {
198+
return;
199+
}
200+
await callKeep.endAllCalls();
201+
}
202+
```
203+
204+
### FAQ
205+
206+
> I don't receive the incoming call
207+
208+
Receiving incoming calls depends on FCM push messages (or the system you use) for handling the call information and displaying it.
209+
Remember FCM push messages not always works due to data-only messages are classified as "low priority". Devices can throttle and ignore these messages if your application is in the background, terminated, or a variety of other conditions such as low battery or currently high CPU usage. To help improve delivery, you can bump the priority of messages. Note; this does still not guarantee delivery. More info [here](https://firebase.flutter.dev/docs/messaging/usage/#low-priority-messages)
210+
211+
> How can I manage the call if the app is terminated and the device is locked?
212+
213+
Even in this scenario, the `backToForeground()` method will open the app and your call P-C-M will be able to work.
214+
215+
20216
## push test tool
21217

22218
Please refer to the [Push Toolkit](/tools/) to test callkeep offline push.

images/sample.png

1.45 MB
Loading

0 commit comments

Comments
 (0)