react-native-voip24h-sdk
v1.0.2
Published
TODO
Downloads
7
Readme
React Native Voip24h-SDK
Mục lục
Tính năng
| Chức năng | Mô tả | | --------- | ----- | | CallKit | • Đăng nhập/Đăng xuất/Refresh kết nối tài khoản SIP • Gọi đi/Nhận cuộc gọi đến • Chấp nhận cuộc gọi/Từ chối cuộc gọi đến/Ngắt máy • Pause/Resume cuộc gọi • Hold/Unhold cuộc gọi • Bật/Tắt mic • Lấy trạng thái mic • Bật/Tắt loa • Lấy trạng thái loa • Transfer cuộc gọi • Send DTMF | | Graph | • Lấy access token • Request API từ: https://docs-sdk.voip24h.vn/ |
Yêu cầu
- OS Platform:
- Android ->
minSdkVersion: 23
- IOS ->
iOS Deployment Target: 11
- Android ->
- Permissions: khai báo và cấp quyền lúc runtime
Android: Trong file
AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.RECORD_AUDIO"/>
IOS: Trong file
Info.plist
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict> <key>NSMicrophoneUsageDescription</key> <string>{Your permission microphone description}</string>
Cài đặt
Step 1: NPM:
npm install react-native-voip24h-sdk
Step 2: Linking module:
- Android:
- Trong file
settings.gradle
include ':react-native-voip24h-sdk' project(':react-native-voip24h-sdk').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-voip24h-sdk/android')
- Trong
build.gradle
:allprojects { repositories { ... maven { name "linphone.org maven repository" url "https://linphone.org/maven_repository/" content { includeGroup "org.linphone.no-video" } } } }
- Trong file
app/build.gradle
android { ... packagingOptions { pickFirst 'lib/x86/libc++_shared.so' pickFirst 'lib/x86_64/libc++_shared.so' pickFirst 'lib/arm64-v8a/libc++_shared.so' pickFirst 'lib/armeabi-v7a/libc++_shared.so' } } dependencies { ... implementation project(':react-native-voip24h-sdk') }
- Trong file
- IOS:
- Trong
ios/Podfile
:... use_frameworks! target 'Your Project' do ... # Comment dòng use_flipper!() # use_flipper!() pod 'linphone-sdk-novideo', :podspec => '../node_modules/react-native-voip24h-sdk/third_party_podspecs/linphone-sdk-novideo.podspec' end
- Trong folder
ios
mở terminal, nhập dòng lệnh:rm -rf Pods/ pod install
Note: Từ react-native vesion > 0.63.0. Nếu build app trên platform ios mà bị lỗi Swift Compiler error: folly/folly-config.h not found -> Could not build Objective-C module 'linphone'. • Fix: Trong file Pods/RCT-Folly/folly/portability/Config.h, comment dòng #include <folly/folly-config.h>
- Trong
Sử dụng
import { NativeEventEmitter } from 'react-native';
import { GraphModule, SipModule, MethodRequest } from 'react-native-voip24h-sdk';
// TODO: To do something with GraphModule, SipModule
CallKit
- Thay đổi: CHANGELOG.md
- Tính năng
| Phương thức và tham số | Kết quả trả về và thuộc tính | Ví dụ |
| :----------------------------------------------------------- | :--------------------------: | :-----------------------------------------: |
| • Khởi tạo: initializeModule()
| None | SipModule.initializeModule()
|
| • Login SIP: registerSipAccount(String, String, String)
| None | SipModule.registerSipAccount("extension", "password", "IP")
|
| • Trạng thái đăng kí SIP: getSipRegistrationState()
| state: string error: string | SipModule.getSipRegistrationState().then(state => {}).catch(error => {})
|
| • Logout SIP: unregisterSipAccount()
| None | SipModule.unregisterSipAccount()
|
| • Refresh kết nối SIP: refreshRegisterSipAccount()
| None | SipModule.refreshRegisterSipAccount()
|
| • Gọi đi: call(String)
| None | SipModule.call("phoneNumber")
|
| • Ngắt máy: hangup()
| None | SipModule.hangup()
|
| • Chấp nhận cuộc gọi đến: acceptCall()
| None | SipModule.acceptCall()
|
| • Từ chối cuộc gọi đến: decline()
| None | SipModule.decline()
|
| • Transfer cuộc gọi: transfer(String)
| None | SipModule.transfer("extension")
|
| • Call id: getCallId()
| state: string error: string | SipModule.getCallId().then(callId => {}).catch(error => {})
|
| • Số lượng cuộc gọi nhỡ: getMissedCalls()
| result: int error: string | SipModule.getMissedCalls().then(result => {}).catch(error => {})
|
| • Pause cuộc gọi: pause()
| None | SipModule.pause()
|
| • Resume cuộc gọi: resume()
| None | SipModule.resume()
|
| • Bật/Tắt mic: toggleMic()
| result: boolean error: string | SipModule.toggleMic().then(result => {}).catch(error => {})
|
| • Trạng thái mic: isMicEnabled()
| result: boolean error: string | SipModule.isMicEnabled().then(result => {}).catch(error => {})
|
| • Bật/Tắt loa: toggleSpeaker()
| result: boolean error: string | SipModule.toggleSpeaker().then(result => {}).catch(error => {})
|
| • Trạng thái loa: isSpeakerEnabled()
| result: boolean error: string | SipModule.isSpeakerEnabled().then(result => {}).catch(error => {})
|
| • Send DTMF: sendDtmf(String)
| None | SipModule.sendDtmf("number#")
|
- Event listener SIP:
• Đăng kí event dạng object • Đăng kí event trong React.useEffect()
| Tên sự kiện | Kết quả trả về và thuộc tính | Đặc tả thuộc tính | | :---------------------------------------------- | :--------------------------------------------------------------- | :---------------------------------------------------- | | AccountRegistrationStateChanged | body = { registrationState: String, message: String } | • registrationState: trạng thái kết nối của sip (None/Progress/Ok/Cleared/Failed) • message: chuỗi mô tả trạng thái | | Ring | body = { extension: String, phone: String type: String } | • extension: máy nhánh • phone: số điện thoại người (gọi/nhận) • type: loại cuộc gọi(inbound/outbound) | | Up | body = { callId: String } | • callId: mã cuộc gọi | Hangup | body = { duration: Long } | • duration: thời gian đàm thoại (milliseconds) | Paused | None | Resuming | None | Missed | body = { phone: String, totalMissed: Int } | • phone: số điện thoại người gọi • totalMissed: tổng cuộc gọi nhỡ | Error | body = { message: String } | • message: chuỗi mô tả trạng thái lỗi
- Ví dụ lắng nghe event callback
const callbacks = {
AccountRegistrationStateChanged: (body) => console.log(`AccountRegistrationStateChanged -> registrationState: ${body.registrationState} - message: ${body.message}`),
Ring: (body) => console.log(`Ring -> extension: ${body.extension} - phone: ${body.phone} - type: ${body.type}`),
Up: (body) => console.log(`Up -> callId: ${body.callId}`),
Hangup: (body) => console.log(`Hangup -> duration: ${body.duration}`),
Paused: () => console.log("Paused"),
Resuming: () => console.log("Resuming"),
Missed: (body) => console.log(`Missed -> phone: ${body.phone} - Total missed: ${body.totalMissed}`),
Error: (body) => console.log(`Error -> message: ${body.message}`)
}
React.useEffect(() => {
let eventEmitter = new NativeEventEmitter(SipModule)
const eventListeners = Object.entries(callbacks).map(
([event, callback]) => {
return eventEmitter.addListener(event, callback)
}
)
return () => {
eventListeners.forEach((item) => {
item.remove();
})
};
}, []);
Push Notification
IOS: Chúng tôi sử dụng Apple Push Notification service (APNs) cho thông báo đẩy cuộc gọi đến khi app ở trạng thái background
Step 1: Tạo APNs Auth Key
- Truy cập Apple Developer để tạo Certificates
- Chọn chứng nhận VoIP Services Certificate
- Chọn ID ứng dụng của bạn. Mỗi ứng dụng bạn muốn sử dụng với dịch vụ VoIP đều yêu cầu chứng chỉ dịch vụ VoIP riêng. Chứng chỉ dịch vụ VoIP dành riêng cho ID ứng dụng cho phép máy chủ thông báo (Voip24h) kết nối với dịch vụ VoIP để gửi thông báo đẩy về ứng dụng của bạn.
- Download file chứng chỉ và mở bằng Keychain Access
- Export chứng chỉ sang định dạng .p12
- Convert file chứng chỉ .p12 sang định dạng .pem và submit cho Voip24h cấu hình
openssl pkcs12 -in path_your_certificate.p12 -out path_your_certificate.pem -nodes
- Truy cập Apple Developer để tạo Certificates
Step 2: Cấu hình project app của bạn để nhận thông báo đẩy cuộc gọi đến -> Từ IOS 10 trở lên, sử dụng CallKit + PushKit
- Để sử dụng CallKit Framework + PushKit FrameWork, chúng tôi khuyến khích sử dụng thư viện react-native-callkeep và react-native-voip-push-notification
npm i react-native-voip-push-notification npm i react-native-callkeep cd ios pod install
- Tại project của bạn thêm Push Notifications và tích chọn Voice over IP, Background fetch, Remote notifications, Background processing (Background Modes) trong Capabilities.
- Khi khởi động ứng dụng react-native-voip-push-notification sẽ tạo mã thông báo đăng kí cho ứng dụng khách. Sử dụng mã này để đăng kí lên server Voip24h
// App.js import VoipPushNotification from "react-native-voip-push-notification" import { requestNotifications } from 'react-native-permissions' ... VoipPushNotification.addEventListener('register', (token) => { // tokenGraph: access token được generate từ API Graph // token: token device pushkit // sipConfiguration: thông số sip khi đăng kí máy nhánh // os: Platform.OS (android/ios) // bundleId: bundle id của ios // isProduction: true(production) / false(dev) // uniqueId: device mac PushNotificationModule.registerPushNotification(tokenGraph, token, sipConfiguration, os, bundleId, true, uniqueId) .then(response => { console.log(response.data) }).catch(error => { console.log(error.response.data.message) }) }) VoipPushNotification.registerVoipToken()
Chúng tôi khuyến khích sử dụng thư viện react-native-device-info để lấy mã device mac và bundle id
- Cấp quyền thông báo trên ios
// App.js import { requestNotifications } from 'react-native-permissions' requestNotifications(['alert', 'sound']).then(({status, settings}) => {})
- Đăng kí nhận thông báo đẩy từ Voip24h Server
• Important Note: Sau khi nhận thông báo đẩy từ Voip24h Server, như đã đề cập cơ chế Callkit, PushKit ở trên thì phải hiển thị màn hình cuộc gọi của hệ thống (cuộc gọi giả) trước, thực thi Login lại máy nhánh ngay sau đó để nhận tín hiệu cuộc gọi thật từ Voip24h thông qua bản tin event Ring, lúc này mọi action call như answer/reject mới hoạt động.
// App.js import RNCallKeep from 'react-native-callkeep' import VoipPushNotification from "react-native-voip-push-notification" React.useEffect(() => { ... // Push Notification if(Platform.OS === 'ios') { const options = { ios: { appName: 'example', } } RNCallKeep.setup(options) RNCallKeep.addEventListener('answerCall', ({callUUID}) => { console.log("accept: " + callUUID) AcceptCall() }) RNCallKeep.addEventListener('endCall', ({callUUID}) => { console.log("endCall: " + callUUID + " - " + appState.current) if(appState.current.match(/inactive|background/)) { Hangup() } else { Decline() } }) VoipPushNotification.addEventListener('notification', (notification) => { console.log('Message handled in the background!', notification) callId = notification.uuid Login() }) } ... return () => { ... RNCallKeep.removeEventListener('answerCall') RNCallKeep.removeEventListener('endCall') callId = '' } }, [])
- Cấu hình ở project ios native
// AppDelegate.mm #import <PushKit/PushKit.h> #import "RNVoipPushNotificationManager.h" #import "RNCallKeep.h" #import "Payload.h" - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [RNVoipPushNotificationManager voipRegistration]; ... } .... - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type { [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type]; } - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { NSLog(@"didReceiveIncomingPushWithPayload: %@", payload.dictionaryPayload); NSString *fromNumber = payload.dictionaryPayload[@"from_number"]; NSString *toNumber = payload.dictionaryPayload[@"to_number"]; NSString *uuid = [[NSUUID UUID] UUIDString]; NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; [dict setObject:[uuid lowercaseString] forKey:@"uuid"]; [dict setObject:fromNumber forKey:@"from_number"]; [dict setObject:toNumber forKey:@"to_number"]; PushPayload *customPayload = [[PushPayload alloc] init]; customPayload.customDictionaryPayload = dict; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:customPayload forType:(NSString *)type]; }); [RNCallKeep reportNewIncomingCall:uuid handle:@"example" handleType:@"generic" hasVideo:false localizedCallerName:fromNumber supportsHolding:false supportsDTMF:false supportsGrouping:false supportsUngrouping:false fromPushKit:true payload:nil withCompletionHandler:completion]; completion(); }
- Để huỷ đăng kí nhận Push Notification
// App.js import { PushNotificationModule } from 'react-native-voip24h-sdk' // sipConfiguration: thông số sip khi đăng kí máy nhánh // os: Platform.OS (android/ios) // packageId: package id của android / bundle id của ios PushNotificationModule.unregisterPushNotification(sipConfiguration, os, packageId) .then(response => { console.log(response.data) }).catch(error => { console.log(error.response.data.message) })
Android: Chúng tôi sử dụng Firebase Cloud Messaging (FCM) cho thông báo đẩy cuộc gọi đến khi app ở trạng thái background
Step 1: Tạo API Token
Step 2: Cấu hình project app của bạn để nhận thông báo đẩy cuộc gọi đến -> chúng tôi khuyến khích bạn sử dụng thư viện React Native Firebase
- NPM
npm install --save @react-native-firebase/app npm install --save @react-native-firebase/messaging
Theo dõi docs React Native Firebase để cấu hình project app của bạn
- Khi khởi động ứng dụng React Native Firebase sẽ tạo mã thông báo đăng kí cho ứng dụng khách. Sử dụng mã này để đăng kí lên server Voip24h
// App.js import { Platform } from 'react-native' import { PushNotificationModule } from 'react-native-voip24h-sdk' import messaging from '@react-native-firebase/messaging' ... await messaging().registerDeviceForRemoteMessages() const token = await messaging().getToken() // tokenGraph: access token được generate từ API Graph // token: token device firebase // sipConfiguration: thông số sip khi đăng kí máy nhánh // os: Platform.OS (android/ios) // packageId: package id của android / bundle id của ios // isProduction: true(production) / false(dev) // uniqueId: device mac PushNotificationModule.registerPushNotification(tokenGraph, token, sipConfiguration, os, packageId, isProduction, uniqueId) .then(response => { console.log(response.data) }).catch(error => { console.log(error.response.data.message) })
Chúng tôi khuyến khích sử dụng thư viện react-native-device-info để lấy mã device mac và package id
- Phiên bản từ Android 13 (SDK 32) trở đi sẽ yêu cầu quyền thông báo để nhận Push Notification https://developer.android.com/develop/ui/views/notifications/notification-permission. Vui lòng cấp quyền runtime POST_NOTIFICATIONS trước khi sử dụng
- Để nhận được thông báo đẩy khi app ở trạng thái background, cần xử lý bên ngoài logic ứng dụng cụ thể trong your-project/index.js. Khi nhận thông báo đẩy, vui lòng đăng kí lại máy nhánh để nhận tín hiệu cuộc gọi đến
// index.js import { SipModule, SipConfigurationBuilder, TransportType } from 'react-native-voip24h-sdk' import messaging from '@react-native-firebase/messaging'; ... messaging().setBackgroundMessageHandler(async (remoteMessage) => { console.log('Message handled in the background!', remoteMessage); let eventEmitter = new NativeEventEmitter(SipModule) eventEmitter.addListener('Ring', event => { // display your notification }); Login() }) function Login() { var sipConfiguration = new SipConfigurationBuilder("extension", "password", "ip") .setPort(port) .setTransportType(TransportType.Udp) .setKeepAlive(true) .build() SipModule.registerSipAccount(sipConfiguration) }
- Để huỷ đăng kí nhận Push Notification
// App.js import { PushNotificationModule } from 'react-native-voip24h-sdk' // sipConfiguration: thông số sip khi đăng kí máy nhánh // os: Platform.OS (android/ios) // packageId: package id của android / bundle id của ios PushNotificationModule.unregisterPushNotification(sipConfiguration, os, packageId) .then(response => { console.log(response.data) }).catch(error => { console.log(error.response.data.message) })
Graph
• key và security certificate(secert) do
Voip24h
cung cấp • request api: method, resource-path. data body tham khảo từ docs https://docs-sdk.voip24h.vn/
| Phương thức | Đặc tả tham số | Kết quả trả về |
| :------------------ | :---------------------- | :------------------------- |
| • Lấy access token: GraphModule.getAccessToken(key, secert, callbacks)
| • key: String, • secert: String • callbacks = { success:(statusCode, message, oauth), error:(errorCode, message) } | success = { statusCode: Int, message: String, oauth: Object (gồm các thuộc tính: token, createAt, expired, isLongAlive) }, error = { errorCode: Int, message: String } |
| • Request API: GraphModule.sendRequest(method, endpoint, token, params, callback)
| • method: MethodRequest(MethodRequest.POST, MethodRequest.GET,...) • resource-path: đường dẫn tài nguyên của URL: "call/find", "call/findone",... • token: access token • params: data body dạng object như { offset: 0, limit: 25 } • callbacks = { success:(statusCode, message, jsonObject), error:(errorCode, message) } | success = { statusCode: Int, message: String, jsonObject: Object (kết quả response dạng json object) }, error = { errorCode: Int, message: String } |
| • Lấy data object: GraphModule.getData(jsonObject)
| jsonObject: kết quả response | object: Object (gồm các thuộc tính được mô tả ở dữ liệu trả về trong docs https://docs-sdk.voip24h.vn/ |
| • Lấy danh sách data object: GraphModule.getListData(jsonObject)
| jsonObject: kết quả response | object: Object (mỗi object gồm các thuộc tính được mô tả ở dữ liệu trả về trong docs https://docs-sdk.voip24h.vn/) |
License
The MIT License (MIT)
Copyright (c) 2022 VOIP24H
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.