eTelecom docs
English
English
  • INSTRUCTIONS FOR USE
    • Administration page for cs.etelecom
    • Google Chrome Extension
    • App eTelecom
  • API INTEGRATION
    • Shop
      • Account
      • Usage
    • Partner
      • Account
      • Usage
    • VPBX
      • VoIP SDK
        • Android
        • iOS
        • Web
        • Flutter
      • PBX REST APIs
        • Partner Get Tenant List
        • Partner Add Hotline
        • Partner Get Hotline List
        • Partner Activate Tenant
        • Partner Add Hotline To Tenant
        • Partner Removed Hotline From Tenant
        • Partner Remove Hotline
        • Create Tenant
        • Get Tenant information
        • Get Driver Config
        • Get hotline list
        • Create Account User
        • Get List User
        • Create extension
        • Get extension information
        • Get extension list
        • Assign extension to user
        • Change hotline for extension
        • Remove User Of Extension
        • Get call history
    • Zalo Cloud
      • Instructions for connecting Zalo Cloud
      • Zalo Cloud API
        • Create OA authorization link
        • Connect OA
        • Get refresh token
        • Get OA list
        • Get OA information
        • Update Webhook for OA
        • Get list of users
        • Send Text Consulting
        • Send Consulting message according to user information request form
        • Send advice message with sticker
        • Send message Consulting with attached photo
        • Send message Consulting attached file
        • Send transaction message
        • Upload file
        • Send request for calling permission
        • Check if the customer has granted calling permission
        • Get list of requests for calling permission
        • Create a news template
        • Get sample details
        • Get list of news samples
        • Journey Token Creation
        • Get Journey Token Details
        • Get Journey Token List
        • Get message list
        • Get message details
        • Send ZNS
        • Send ZNS with Journey Token
  • SMS BRANDNAME
    • User manual
    • SMS API
      • Send SMS
      • Get message status
      • Get sample details
Powered by GitBook
On this page
  • Configuration for iOS
  • Configuration for Android
  • Configuration for Flutter UI
  1. API INTEGRATION
  2. VPBX
  3. VoIP SDK

Flutter

PreviousWebNextPBX REST APIs

Last updated 5 months ago

Configuration for iOS

In file AppDelegate.swift:

```swift
import UIKit
import Flutter
import PushKit
import UserNotifications
import PortSIPVoIPSDK

@UIApplicationMain class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate {
  
  private let channel = "name_channel"
  
  private var portsipService: PortsipService! = PortsipService()
  
  override func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
  ) -> Bool {
  
    UserDefaults.standard.register(defaults: ["CallKit": true])
    UserDefaults.standard.register(defaults: ["PushNotification": true])
    UserDefaults.standard.register(defaults: ["ForceBackground": true])
  
    fController = window?.rootViewController as? FlutterViewController
    
    FlutterMethodChannel(name: channel, binaryMessenger: fController.binaryMessenger).setMethodCallHandler({
      [weak self] (call: FlutterMethodCall, result: FlutterResult) -> Void in
      // Note: this method is invoked on the UI thread.
      
      switch call.method {
      case "registerPortsip":
        let args = call.arguments as? [String: Any]
        let username = args?["username"] as? String
        let password = args?["password"] as? String
        let domain = args?["domain"] as? String
        let server = args?["sipServer"] as? String
        
        if username != nil && password != nil && domain != nil {
          let res = self?.registerPortSip(username: username!, password: password!, domain: domain!, sipServer: server!)
          if res == 0 || res == -60021 || res == -60095 || res == -60098 {
            result(Int32(res!))
          } else {
            result(FlutterError(code: "REGISTER FAILED", message: "Kết nối không thành công.", details: nil))
          }
        } else {
          result(FlutterError(code: "NOT AUTHENTICATED", message: "Username và password không đúng.", details: nil))
        }
        
      case "unregisterPortsip":
        if (self?.portsipService != nil) {
          self?.updatePushStatusToSipServer(willPush: false)
          self?.portsipService.unregisterPortsip()
        }
        
      case "callOut":
        let args = call.arguments as? [String: Any]
        let phoneNumber = args?["phoneNumber"] as? String
        let videoCall = args?["videoCall"] as? Bool
        
        if phoneNumber != nil {
          let res = self?.portsipService.callOut(phoneNumber: phoneNumber!, videoCall: videoCall ?? false)
          if res! {
            result(nil)
          } else {
            result(FlutterError(code: "CALL FAILED", message: "Không thể thực hiện cuộc gọi", details: nil))
          }
        }
      case "hangUp":
        let res = self?.portsipService.hangUp()
        if res! {
          result(nil)
        } else {
          result(FlutterError(code: "HANGUP FAILED", message: "Không thể kết thúc cuộc gọi", details: nil))
        }
      case "answerCall":
        let res = self?.portsipService.answerCall()
        if res! {
          result(nil)
        } else {
          result(FlutterError(code: "ANSWER_CALL FAILED", message: "Không thể trả lời cuộc gọi", details: nil))
        }
      case "rejectCall":
        let res = self?.portsipService.rejectCall()
        if res! {
          result(nil)
        } else {
          result(FlutterError(code: "REJECT_CALL FAILED", message: "Không thể từ chối cuộc gọi", details: nil))
        }
      case "hold":
        let res = self?.portsipService.hold()
        if res! {
          result(nil)
        } else {
          result(FlutterError(code: "HOLD_CALL FAILED", message: "Không thể giữ máy", details: nil))
        }
      case "unHold":
        let res = self?.portsipService.unHold()
        if res! {
          result(nil)
        } else {
          result(FlutterError(code: "UNHOLD_CALL FAILED", message: "Không thể tiếp tục cuộc gọi", details: nil))
        }
      case "speakerOn":
        self?.portsipService.speakerOn()
        result(nil)
      case "speakerOff":
        self?.portsipService.speakerOff()
        result(nil)
      case "microphoneOn":
        self?.portsipService.turnOnMicrophone()
        result(nil)
      case "microphoneOff":
        self?.portsipService.turnOffMicrophone()
        result(nil)
      case "frontCamera":
        self?.portsipService.switchToFrontCamera()
        result(nil)
      case "backCamera":
        self?.portsipService.switchToBackCamera()
        result(nil)
      case "cameraOn":
        self?.portsipService.turnOnCamera()
        result(nil)
      case "cameraOff":
        self?.portsipService.turnOffCamera()
        result(nil)
        
      default:
        result(FlutterMethodNotImplemented)
      }
    })
    
    GeneratedPluginRegistrant.register(with: self)
    return super.application(application, didFinishLaunchingWithOptions: launchOptions)
  }
  
  private func registerPortSip(username: String, password: String, domain: String, sipServer: String) -> Int32 {
    PortsipService.fController = fController
    
    if !CallManager.portsipRegistered {
      CallManager.portsipExtension = username
      CallManager.portsipPassword = password
      CallManager.portsipDomain = domain
      CallManager.portsipServer = sipServer
      
      portsipService.registerPortsip()
    } else {
      portsipService.refreshRegistrationPortsip()
    }
    
    return 0
  }
  
}

```

Configuration for Android

```kotlin

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.util.Log
import android.view.KeyEvent
import androidx.annotation.NonNull
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.portsip.PortSipErrorcode
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel

@RequiresApi(Build.VERSION_CODES.O)
class MainActivity : FlutterActivity() {
  
  companion object {
    lateinit var shared: MainActivity
    const val channel = "name_channel"
  }
  
  override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
    super.configureFlutterEngine(flutterEngine)
    
    shared = this
    PortsipService.engineF = flutterEngine
  
    MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler { call, result ->
      // Note: this method is invoked on the main thread.
      when (call.method) {
        "registerPortsip" -> {
          val username = call.argument<String>("username")
          val password = call.argument<String>("password")
          val domain = call.argument<String>("domain")
          val server = call.argument<String>("sipServer")
    
          if (username != null && password != null && domain != null && server != null) {
            val res = registerPortsip(username, password, domain, server)
            if (res == 0 || res == PortSipErrorcode.ECoreAlreadyRegistered ||
              res == PortSipErrorcode.ECoreAllowOnlyOneUser ||
              res == PortSipErrorcode.ECoreCreateTransportFailure
            ) {
              result.success(res)
            } else {
              result.error("REGISTER FAILED", "Kết nối không thành công.", null)
            }
          } else {
            result.error("NOT AUTHENTICATED", "Username và password không đúng.", null)
          }
        }
        "unregisterPortsip" -> {
          unregisterPortsip()
        }
        "callOut" -> {
          val phoneNumber = call.argument<String>("phoneNumber")
          val videoCall = call.argument<Boolean>("videoCall")

          if (phoneNumber != null) {
            val res = callOut(phoneNumber, videoCall ?: false)
            if (res) {
              result.success(null)
            } else {
              result.error("CALL FAILED", "Không thể thực hiện cuộc gọi", null)
            }
          }
        }
        "hangUp" -> {
          val res = hangUp()
          if (res) {
            result.success(null)
          } else {
            result.error("HANGUP FAILED", "Không thể kết thúc cuộc gọi", null)
          }
        }
        "answerCall" -> {
          val res = answerCall()
          if (res) {
            result.success(null)
          } else {
            result.error("ANSWER_CALL FAILED", "Không thể trả lời cuộc gọi", null)
          }
        }
        "rejectCall" -> {
          val res = rejectCall()
          if (res) {
            result.success(null)
          } else {
            result.error("REJECT_CALL FAILED", "Không thể từ chối cuộc gọi", null)
          }
        }
        "hold" -> {
          val res = hold()
          if (res) {
            result.success(null)
          } else {
            result.error("HOLD FAILED", "Không thể giữ máy", null)
          }
        }
        "unHold" -> {
          val res = unHold()
          if (res) {
            result.success(null)
          } else {
            result.error("UN_HOLD FAILED", "Không thể tiếp tục giữ máy", null)
          }
        }
        "speakerOn" -> {
          PortsipService.shared?.speakerOn()
          result.success(null)
        }
        "speakerOff" -> {
          PortsipService.shared?.speakerOff()
          result.success(null)
        }
        "microphoneOn" -> {
          PortsipService.shared?.turnOnMicrophone()
          result.success(null)
        }
        "microphoneOff" -> {
          PortsipService.shared?.turnOffMicrophone()
          result.success(null)
        }
        "frontCamera" -> {
          PortsipService.shared?.switchToFrontCamera()
          result.success(null)
        }
        "backCamera" -> {
          PortsipService.shared?.switchToBackCamera()
          result.success(null)
        }
        "cameraOn" -> {
          PortsipService.shared?.turnOnCamera()
          result.success(null)
        }
        "cameraOff" -> {
          PortsipService.shared?.turnOffCamera()
          result.success(null)
        }
        "finishDisposingCamera" -> {
            val intent = Intent(this, VideoCallActivity::class.java)
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            startActivity(intent)
        }
        else -> {
          result.notImplemented()
        }
      }
    }
  }
  
  
  private fun registerPortsip(username: String, password: String, domain: String, server: String): Int {

    val sharedPref = getSharedPreferences("CallManager", MODE_PRIVATE) ?: return 0
    with(sharedPref.edit()) {
      putString(getString(R.string.call_manager_ps_extension), username)
      putString(getString(R.string.call_manager_ps_password), password)
      putString(getString(R.string.call_manager_ps_domain), domain)
      putString(getString(R.string.call_manager_ps_server), server)
      apply()
    }

    Intent(this, PortsipService::class.java).also { intent ->
      startService(intent)
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
      if (PackageManager.PERMISSION_GRANTED != ContextCompat.checkSelfPermission(
          activity, Manifest.permission.BLUETOOTH_CONNECT)
      ) {
        ActivityCompat.requestPermissions(
          activity,
          arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
          0
        )
      }
    }
    
    return 0

  }
  
  private fun unregisterPortsip() {
    if (PortsipService.shared != null) {
      PortsipService.shared!!.unregisterPortsip()
    }
  }
  
  private fun callOut(phoneNumber: String, videoCall: Boolean = false): Boolean {
    return PortsipService.shared?.callOut(phoneNumber, videoCall) ?: false
  }
  
  private fun hangUp(): Boolean {
    return PortsipService.shared?.hangUp() ?: false
  }
  
  private fun answerCall(): Boolean {
    return PortsipService.shared?.answerCall() ?: false
  }
  
  private fun rejectCall(): Boolean {
    return PortsipService.shared?.rejectCall() ?: false
  }
  
  private fun hold(): Boolean {
    return PortsipService.shared?.hold() ?: false
  }
  
  private fun unHold(): Boolean {
    return PortsipService.shared?.unHold() ?: false
  }
  
}

```

Configuration for Flutter UI

const CHANNEL = 'name_channel';
const platform = const MethodChannel(CHANNEL);

static Future<void> portsipRegister() async {
    try {
      await platform.invokeMethod("registerPortsip", {
        'username': extensionNumber,
        'password': extensionPassword,
        'domain': tenantDomain,
        'sipServer': sipServer
      });
    } on PlatformException catch (e) {
       throw e;
    }
  }
  

static Future<void> callOut(String phoneNumber, bool isVideoCall) async {
    try {
      await platform.invokeMethod("callOut", {
        'phoneNumber': phoneNumber, 'videoCall': isVideoCall
      });
    } on PlatformException catch(e) {
      throw e;
    }
  }
  
 static Future<void> portsipHangUp() async {
    try {
      await platform.invokeMethod("hangUp");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> portsipAnswer() async {
    try {
      await platform.invokeMethod("answerCall");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> portsipReject() async {
    try {
     await platform.invokeMethod("rejectCall");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> portsipHold() async {
    try {
      await platform.invokeMethod("hold");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> portsipUnHold() async {
    try {
      await platform.invokeMethod("unHold");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> portsipSpeakerOn() async {
    try {
      await platform.invokeMethod("speakerOn");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> portsipSpeakerOff() async {
    try {
      await platform.invokeMethod("speakerOff");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> microphoneOn() async {
    try {
      await platform.invokeMethod("microphoneOn");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> microphoneOff() async {
    try {
      await platform.invokeMethod("microphoneOff");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> switchToFrontCamera() async {
    try {
      await platform.invokeMethod("frontCamera");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> switchToBackCamera() async {
    try {
      await platform.invokeMethod("backCamera");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> cameraOn() async {
    try {
      await platform.invokeMethod("cameraOn");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static Future<void> cameraOff() async {
    try {
      await platform.invokeMethod("cameraOff");
    } on PlatformException catch (e) {
      throw e;
    }
  }

  static void hookNativeEvents(BuildContext context) {

    platform.setMethodCallHandler((call) async {
      try {
        switch (call.method) {
          case 'onRegisterFailure':

            String code = jsonDecode(call.arguments)["code"] ?? "";

            if (code != callsReader.portsipRegisterFailureCode) {
              //todo if onRegisterFailure
            }

            return;

          case 'callIn':
            String? caller = jsonDecode(call.arguments)["caller"];
            String callingNumber = caller!.split('sip:')[1].split('@')[0];

            bool? isVideoCall = jsonDecode(call.arguments)["isVideo"];

            portsipCallIn(
                phoneNumber: callingNumber,
                isVideoCall: isVideoCall == null ? false : isVideoCall
            );

            return;

          case 'callAnswered':
            if (call.arguments != null && call.arguments.length > 0) {
              String? caller = jsonDecode(call.arguments)["caller"];
            }

            return;

          case 'callEnded':
            //code here

            return;

          case 'sipMessageResponse':
            if (call.arguments == null || call.arguments.length == 0) {
              return;
            }

            String sipMessage = jsonDecode(call.arguments)['sipMessage'];
            String _splitMessage = sipMessage.split('X-Session-Id:')[1];
            if (_splitMessage.isEmpty) {
              return;
            }

            String xSessionId = _splitMessage.substring(0, 18);

            return;

          case 'disposeCamera':
            await callsReader.disposeCamera();

            try {
              await platform.invokeMethod("finishDisposingCamera");
            } on PlatformException catch (e) {
              
            }

            return;

        }
      } catch (e) {
        hookNativeEvents(context);
      }
      return;
    });
  }

See more functions here:

See more functions here:

https://docs.etelecom.vn/tong-dai/sdk/ios
https://docs.etelecom.vn/tong-dai/sdk/android