Tích Hợp HotLine Flutter SDK

Để tích hợp gọi hot line OTT cần 3 bước, tương ứng với 3 hàm trong SDK ALICMM.config, ALICMM.login, ALICMM.startHotlineCall trong đó các tham số key service được đăng ký trên CRM ALI

Vui lòng lấy các key tương ứng và ghi đè lại CRM ALI

Tham số key chứng thực

  final REPLACE_WITH_username = 'REPLACE_WITH_username';
  final REPLACE_WITH_credential = 'REPLACE_WITH_credential';
  final REPLACE_WITH_secret = 'REPLACE_WITH_secret';

Tham số cấu hình websocket

  final REPLACE_WITH_host = 'REPLACE_WITH_host';
  final REPLACE_WITH_hostUrlWebSocket = 'REPLACE_WITH_hostUrlWebSocket';
  final REPLACE_WITH_hostUrlHotlineWebSocket =
      'REPLACE_WITH_hostUrlHotlineWebSocket';
  final REPLACE_WITH_turnHostWebSocket = 'REPLACE_WITH_turnHostWebSocket';
  final REPLACE_WITH_stunHostWebSocket = 'REPLACE_WITH_stunHostWebSocket';

Tham số host line

  final REPLACE_WITH_id = 'REPLACE_WITH_id';
  final REPLACE_WITH_key = 'REPLACE_WITH_key';
  final REPLACE_WITH_code = 'REPLACE_WITH_code';
  final REPLACE_WITH_name = 'REPLACE_WITH_name';
  final REPLACE_WITH_image_url = 'REPLACE_WITH_image_url';

App demo

Github example : https://github.com

Cấu hình

Thêm thư viện trong pubspec.yaml

---
dependencies:
  equatable: ^2.0.3
  flutter_ali_cmm:
    #path local file
    path: ../flutter_ali_cmm

iOS

Ưu cầu iOs tối thiểu: 14.0 Quyền khai báo audio trong Info.plist file.

<dict>
  ...
  <key>NSMicrophoneUsageDescription</key>
  <string>$(PRODUCT_NAME) uses your microphone</string>

Xin thêm quyền audio ở back ground mode Trong Info.plist

<dict>
  ...
  <key>UIBackgroundModes</key>
  <array>
    <string>audio</string>
  </array>

Thêm FW CallKit.frameworks trong Frameworks, Libraries, and Embedded Content

Android

Thêm các quyền trong app/main/ AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.your.package">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_PHONE_CALL"/>
    <uses-permission android:name="android.permission.MANAGE_OWN_CALLS"/>
    <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  ...
</manifest>

Trong thưc mục android build.grade.

allprojects {
    repositories {
        google()
        mavenCentral()
        maven {
            url "https://jitpack.io"
        }
        maven {
            url "https://webgit.taxidayroi.vn/api/v4/projects/430/packages/maven"
            name "GitLab"
            credentials(HttpHeaderCredentials) {
                name = 'Deploy-Token'
                value = 'jQroyDaWNrxxvYN6Z5xY'
            }
            authentication {
                header(HttpHeaderAuthentication)
            }
        }
    }
}

Chỉnh sửa ext.kotlin_version = '1.8.0' verison trong buildscript và build grade classpath 'com.android.tools.build:gradle:7.4.2'

buildscript {
    ext.kotlin_version = '1.8.0'
    repositories {
        google()
        mavenCentral()

    }

    dependencies {
        classpath 'com.android.tools.build:gradle:7.4.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

Trong thưc mục android/app build.grade.

    dependencies {
        ... 
        implementation 'com.tot:audiocall:1.1.0'
    }

Sử dụng flutter_ali_cmm trong flutter

Khai báo package sdk

    import 'package:flutter_ali_cmm/flutter_ali_cmm.dart';

Ưu cầu Xin quyền auudio thông qua hàm ALICMM.getPermission() trước khi thực hiện cuộc gọi

 await ALICMM.getPermission();

Cấu hình môi trường ALICMM.config

    final ser = ALICMMServerConfig(
      //online
      host: REPLACE_WITH_host,
      hostUrlWebSocket: REPLACE_WITH_hostUrlWebSocket,
      hostUrlHotlineWebSocket: REPLACE_WITH_hostUrlHotlineWebSocket,
      turnHostWebSocket: REPLACE_WITH_turnHostWebSocket,
      stunHostWebSocket: REPLACE_WITH_stunHostWebSocket,
    );
    ALICMM.config(ser, 'sandbox');

Sử dụng đăng nhập để chứng thực hợp lệ ALICMM.login qua các key đã đăng ký trước đó.

    ALICMM.login(
      'Số điện thoại đăng nhập app',
      ALICMMCallConfig(
        username: REPLACE_WITH_username,
        credential: REPLACE_WITH_credential,
        secret: REPLACE_WITH_secret,
      ),
    );

Gọi tổng đài ALICMM.startHotlineCall thông qua param tương ứng ALICMMCall.fromHotlineConfig như sau

    var param = ALICMMCall.fromHotlineConfig(
      hotlineConfig: ALICMMHotlineConfig(
        id: REPLACE_WITH_id,
        key: REPLACE_WITH_key,
        code: REPLACE_WITH_code,
        name: REPLACE_WITH_name,
        image: REPLACE_WITH_image_url ,
      ),
      callerId: 'Số điện thoại đăng nhập app',
      callerAvatar: 'url hình ảnh ngừoi gọi',
      username: REPLACE_WITH_username,
      credential: REPLACE_WITH_credential,
      secret: REPLACE_WITH_secret,
    );

    ALICMM.startHotlineCall(param);

Sau khi thêm các sự kiện cần đăng ký 1 event call back để hiện thị màn hình cuộc gọi.

Khai báo event call

    final ALiCMMEventCallbacks _eventCallbacks = ALiCMMEventCallbacks();

Trong hàm init khai báo sự kiện

    _eventCallbacks.setEventCallbacks(
      onUpdatePushKitToken: (pushToken) {
        //Dùng trong cuộc gọi P2P, đăng ký pushkit token
      },
      onNotifyCall: (notifyCallData) async {
         //Dùng trong cuộc gọi P2P, gọi api thông báo có cuộc gọi
      },
      onRequestShowCall: (call) {
        // Hiện màn hình cuộc gọi 
        toCallPageScreen(context, call);
      },
    );

mở màn hình cuộc gọi trong PageCall truyền ALICMMCall được trả về trong call back

    toCallPageScreen(BuildContext context, ALICMMCall call) {
        Future.delayed(Duration.zero, () async {
          Navigator.push(
            context,
            MaterialPageRoute(builder: (context) => PageCall(call)),
          );
        });
    }

Handle event state của cuộc gọi thông qua hàm AliCMMCallEventCallbacks được trả về call back, khi cuộc gọi bắt đầu kết nối

    final AliCMMCallEventCallbacks _callEventCallbacks = AliCMMCallEventCallbacks();

đăng ký event call back trả về khi có trạng thái cuộc gọi diễn ra, khai báo trong init của màn hình cuộc gọi

    _callEventCallbacks.setCallEventCallbacks(
      onCallStateChange: (state) {
        if (mounted) {
          setState(() {
            handleStageCall(state);
          });
        }
      },
      onCallConnectedChange: (connectedState, connectedDate) => {
        if (mounted)
          {
            setState(() {
              callConnectedState = connectedState;
              connectedTime = connectedDate;
              if (callConnectedState ==
                      ALICMMCallConnectedState.ALICMMConnectedStateComplete &&
                  connectedTime != null) {
                handleStageCall(ALICMMCallState.ALICMMCallStateActive);
              }
            })
          }
      },
    );

trong đó, onCallStateChange là trạng thái cuộc gọi diễn ra, gồm các trạng thái ALICMMCallStateEnded : kết thúc cuộc gọi, ALICMMCallStatePending : cuộc gọi đang bắt đầu kết nối, ALICMMCallStateActive: cuộc gọi đã kết nối khi bên tổng đài chấp nhận cuộc gọi, hoặc kết thúc cuộc gọi thì có event trả về trong onCallStateChange trả về trạng thái để handle UI onCallConnectedChange là trạng thái kết nối cuộc gọi đang diễn ra qua qua trạng ALICMMCallConnectedState, khi 2 bên kết nối thành công sẽ trả về thời gian bắt đầu cuộc gọi connectedDate: DateTime != null, để hiện thị thời gian, và trạng thái kết nối ALICMMConnectedStateComplete: thành công, ngược lại ALICMMConnectedStatePending đang kết nối, và thời gian trả về connectedDate: DateTime = null

chi tiết trong UI PageCall trong demo đính kèm.

Các sự kiện handle cuộc gọi

chấp nhận cuộc gọi

    ALICMM.answerIncomingCall();

kết thúc cuộc gọi

    ALICMM.endCall();

Từ chối cuộc gọi

     ALICMM.denyIncomingCall();

Bật tắt mic

    mute = !mute;
    ALICMM.setMuteCall(mute);

Bật tắt loa ngoài

    speaker = !speaker;
    ALICMM.setSpeakOn(speaker);