Flutter来电管理插件flutter_incoming_call的使用

发布于 1周前 作者 sinazl 来自 Flutter

Flutter来电管理插件flutter_incoming_call的使用

插件介绍

flutter_incoming_call 是一个Flutter插件,用于在Flutter应用中显示来电界面。目前该插件处于Alpha版本,尚未准备好用于生产环境。

使用方法

1. 配置Android项目

AndroidManifest.xml文件中添加以下内容:

<activity
    android:name="com.github.alezhka.flutter_incoming_call.IncomingCallActivity"
    android:theme="@style/Theme.AppCompat"
    android:screenOrientation="portrait"
    android:showOnLockScreen="true">
    <intent-filter>
        <action android:name="com.github.alezhka.flutter_incoming_call.activity.ACTION_INCOMING_CALL" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

<receiver android:name="com.github.alezhka.flutter_incoming_call.CallBroadcastReceiver"
    android:enabled="true"
    android:exported="false"/>

2. 配置Flutter插件

在Dart代码中配置插件:

FlutterIncomingCall.configure(
    appName: 'example_incoming_call',
    duration: 30000,
    android: ConfigAndroid(
        vibration: true,
        ringtonePath: 'default',
        channelId: 'calls',
        channelName: 'Calls channel name',
        channelDescription: 'Calls channel description',
    ),
    ios: ConfigIOS(
        iconName: 'AppIcon40x40',
        ringtonePath: null,
        includesCallsInRecents: false,
        supportsVideo: true,
        maximumCallGroups: 2,
        maximumCallsPerCallGroup: 1,
    )
);

3. 监听事件

监听来电相关的事件:

FlutterIncomingCall.onEvent.listen((event) {
    if(event is CallEvent) { // Android | iOS
        // 处理来电事件
    } else if(event is HoldEvent) { // iOS
        // 处理保持事件
    } else if(event is MuteEvent) { // iOS
        // 处理静音事件
    } else if(event is DmtfEvent) { // iOS
        // 处理DTMF事件
    } else if(event is AudioSessionEvent) { // iOS
        // 处理音频会话事件
    }
});

4. 调用API

调用插件提供的API来显示或结束来电:

// 显示来电
FlutterIncomingCall.displayIncomingCall(String uid, String name, String avatar, String handle, String type, bool isVideo);

// 结束单个来电
FlutterIncomingCall.endCall(String uuid);

// 结束所有来电
FlutterIncomingCall.endAllCalls();

示例代码

以下是一个完整的示例代码,展示了如何在Flutter应用中使用flutter_incoming_call插件:

import 'package:flutter/material.dart';
import 'dart:async';

import 'package:flutter_incoming_call/flutter_incoming_call.dart';
import 'package:uuid/uuid.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatefulWidget {
  [@override](/user/override)
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {

  var uuid = Uuid();

  BaseCallEvent? _lastEvent;
  CallEvent? _lastCallEvent;
  HoldEvent? _lastHoldEvent;
  MuteEvent? _lastMuteEvent;
  DmtfEvent? _lastDmtfEvent;
  AudioSessionEvent? _lastAudioSessionEvent;

  void _incomingCall() {
    final uid = uuid.v4();
    final name = 'Daenerys Targaryen';
    final avatar = 'https://scontent.fhel6-1.fna.fbcdn.net/v/t1.0-9/62009611_2487704877929752_6506356917743386624_n.jpg?_nc_cat=102&_nc_sid=09cbfe&_nc_ohc=cIgJjOYlVj0AX_J7pnl&_nc_ht=scontent.fhel6-1.fna&oh=ef2b213b74bd6999cd74e3d5de235cf4&oe=5F6E3331';
    final handle = 'example_incoming_call';
    final type = HandleType.generic;
    final isVideo = true;
    FlutterIncomingCall.displayIncomingCall(uid, name, avatar, handle, type, isVideo);
  }

  void _endCurrentCall() {
    if(_lastEvent != null && _lastCallEvent != null) {
      FlutterIncomingCall.endCall(_lastCallEvent!.uuid);
    }
  }

  void _endAllCalls() {
    FlutterIncomingCall.endAllCalls();
  }

  [@override](/user/override)
  void initState() {
    super.initState();
    FlutterIncomingCall.configure(
      appName: 'example_incoming_call',
      duration: 30000,
      android: ConfigAndroid(
        vibration: true,
        ringtonePath: 'default',
        channelId: 'calls',
        channelName: 'Calls channel name',
        channelDescription: 'Calls channel description',
      ),
      ios: ConfigIOS(
        iconName: 'AppIcon40x40',
        ringtonePath: null,
        includesCallsInRecents: false,
        supportsVideo: true,
        maximumCallGroups: 2,
        maximumCallsPerCallGroup: 1,
      )
    );
    FlutterIncomingCall.onEvent.listen((event) {
      setState(() { _lastEvent = event; });
      if(event is CallEvent) {
        setState(() { _lastCallEvent = event; });
      } else if(event is HoldEvent) {
        setState(() { _lastHoldEvent = event; });
      } else if(event is MuteEvent) {
        setState(() { _lastMuteEvent = event; });
      } else if(event is DmtfEvent) {
        setState(() { _lastDmtfEvent = event; });
      } else if(event is AudioSessionEvent) {
        setState(() { _lastAudioSessionEvent = event; });
      }
    });
  }

  [@override](/user/override)
  void dispose() {
    _endAllCalls();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Plugin example app'),
        ),
        body: SingleChildScrollView(
          child: Column(
            mainAxisSize: MainAxisSize.max,
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              TextButton(
                child: Text('立即来电'),
                onPressed: _incomingCall,
              ),
              SizedBox(height: 16),
              TextButton(
                child: Text('5秒后来电'),
                onPressed: () => Future.delayed(Duration(seconds: 5), _incomingCall),
              ),
              SizedBox(height: 16),
              TextButton(
                child: Text('结束当前来电'),
                onPressed: _endCurrentCall,
              ),
              SizedBox(height: 16),
              TextButton(
                child: Text('结束所有来电'),
                onPressed: _endAllCalls,
              ),
              SizedBox(height: 16),
              Text(
                '最新事件:',
                style: TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.bold,
                ),
              ),
              Text(
                _lastEvent != null ? _lastEvent.toString() : '无事件',
                style: TextStyle(
                    fontSize: 16
                ),
              ),
              if(_lastCallEvent != null) ...[
                Text(
                  '最新来电事件:',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  _lastCallEvent.toString(),
                  style: TextStyle(
                      fontSize: 16
                  ),
                )
              ],
              if(_lastHoldEvent != null) ...[
                Text(
                  '最新保持事件:',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  _lastHoldEvent.toString(),
                  style: TextStyle(
                      fontSize: 16
                  ),
                )
              ],
              if(_lastMuteEvent != null) ...[
                Text(
                  '最新静音事件:',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  _lastMuteEvent.toString(),
                  style: TextStyle(
                      fontSize: 16
                  ),
                )
              ],
              if(_lastDmtfEvent != null) ...[
                Text(
                  '最新DTMF事件:',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  _lastDmtfEvent.toString(),
                  style: TextStyle(
                      fontSize: 16
                  ),
                )
              ],
              if(_lastAudioSessionEvent != null) ...[
                Text(
                  '最新音频会话事件:',
                  style: TextStyle(
                    fontSize: 16,
                    fontWeight: FontWeight.bold,
                  ),
                ),
                Text(
                  _lastAudioSessionEvent.toString(),
                  style: TextStyle(
                      fontSize: 16
                  ),
                )
              ]
            ],
          ),
        ),
      ),
    );
  }
}

更多关于Flutter来电管理插件flutter_incoming_call的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter来电管理插件flutter_incoming_call的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何在Flutter项目中使用flutter_incoming_call插件的示例代码。这个插件允许你在Flutter应用中处理来电显示和管理。

首先,确保你的Flutter项目已经设置好,并且已经添加了flutter_incoming_call插件。你可以在pubspec.yaml文件中添加以下依赖项:

dependencies:
  flutter:
    sdk: flutter
  flutter_incoming_call: ^x.y.z  # 请替换为最新版本号

然后运行flutter pub get来安装依赖。

1. 配置Android权限

android/app/src/main/AndroidManifest.xml中添加必要的权限:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.yourapp">

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>

    <!-- 其他配置 -->

</manifest>

2. 配置iOS权限

ios/Runner/Info.plist中添加必要的权限配置:

<key>NSMicrophoneUsageDescription</key>
<string>App needs access to microphone</string>
<key>NSCameraUsageDescription</key>
<string>App needs access to camera</string>
<key>UIBackgroundModes</key>
<array>
    <string>voip</string>
</array>

3. 使用插件代码

在Flutter项目的lib目录下创建一个新的Dart文件,比如call_manager.dart,并添加以下代码:

import 'package:flutter/material.dart';
import 'package:flutter_incoming_call/flutter_incoming_call.dart';

class CallManager {
  static FlutterIncomingCall? flutterIncomingCall;

  static void init() {
    flutterIncomingCall = FlutterIncomingCall();

    // 监听来电事件
    flutterIncomingCall?.incomingCallReceived().listen((event) {
      print("Received incoming call: ${event.callInfo.callerNumber}");
      // 显示来电界面
      showIncomingCallUI(event.callInfo);
    });

    // 监听挂断事件
    flutterIncomingCall?.callEnded().listen((event) {
      print("Call ended: ${event.callInfo.callerNumber}");
      // 隐藏来电界面
      hideIncomingCallUI();
    });

    // 监听接听事件
    flutterIncomingCall?.callAnswered().listen((event) {
      print("Call answered: ${event.callInfo.callerNumber}");
    });
  }

  static void showIncomingCallUI(CallInfo callInfo) {
    // 你可以在这里显示一个自定义的来电界面
    // 这里只是一个简单的示例,你可以使用Material或Cupertino组件来构建更复杂的UI
    showDialog(
      context: YourAppContextHere,  // 请替换为你的上下文
      builder: (context) => AlertDialog(
        title: Text('Incoming Call'),
        content: Text('Caller: ${callInfo.callerNumber}'),
        actions: <Widget>[
          TextButton(
            onPressed: () {
              // 拒绝来电
              flutterIncomingCall?.rejectCall(callInfo.uuid);
              Navigator.of(context).pop();
            },
            child: Text('Reject'),
          ),
          TextButton(
            onPressed: () {
              // 接听来电
              flutterIncomingCall?.answerCall(callInfo.uuid);
              Navigator.of(context).pop();
            },
            child: Text('Answer'),
          ),
        ],
      ),
    );
  }

  static void hideIncomingCallUI() {
    // 隐藏来电界面的逻辑,比如关闭Dialog
    // 这里只是示例,实际中你需要根据你的UI逻辑来处理
    Navigator.of(YourAppContextHere).pop();  // 请替换为你的上下文
  }
}

4. 在主应用中使用

在你的主应用文件(通常是main.dart)中初始化CallManager

import 'package:flutter/material.dart';
import 'call_manager.dart';

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  CallManager.init();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Flutter Incoming Call Example'),
        ),
        body: Center(
          child: Text('Check your console for incoming call logs.'),
        ),
      ),
    );
  }
}

注意事项

  • 确保你在适当的上下文中使用Navigator,例如你可以通过依赖注入或者全局状态管理(如Provider、Riverpod等)来传递上下文。
  • 根据你的应用需求,可能需要更复杂的UI和逻辑来处理来电显示。
  • 插件的使用可能会因平台(Android和iOS)的不同而有所差异,请确保测试你的应用在两个平台上的行为。

希望这个示例能帮助你在Flutter项目中集成和使用flutter_incoming_call插件!

回到顶部