You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Flutter开发VoIP通话应用:如何在锁屏显示通话操作Widget?

Hey there! Building a VoIP app with lock-screen call controls (so users can answer/decline without unlocking) is totally feasible in Flutter, but you’ll need to lean on platform-specific native APIs since lock-screen behavior is tightly governed by iOS and Android. Let me walk you through a practical, step-by-step solution:

Core Approach

Flutter doesn’t have direct access to lock-screen UI controls out of the box, so we’ll use a combination of:

  • Native platform frameworks: Android’s InCallService and iOS’s CallKit (these are the only ways to get system-level lock-screen call interfaces that OSes trust)
  • Flutter plugins: A well-maintained plugin to bridge native functionality to your Dart code, avoiding writing full native code from scratch

This plugin wraps both Android’s InCallService and iOS’s CallKit, giving you a unified API to handle incoming calls, lock-screen UI, and call state callbacks. It’s the most popular choice for Flutter VoIP apps.

Step 1: Set Up Dependencies

Add the plugin to your pubspec.yaml:

dependencies:
  flutter_callkit_incoming: ^latest_version # Check pub.dev for the latest version

Run flutter pub get to install it.

Step 2: Platform-Specific Configuration

Android

  1. Add Permissions & Service to AndroidManifest.xml:
    Open android/app/src/main/AndroidManifest.xml and add these lines inside the <manifest> tag:
    <!-- Required permissions -->
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_CALLS" />
    
    <!-- Register InCallService -->
    <application ...>
        <service
            android:name="com.hiennv.flutter_callkit_incoming.CallkitIncomingService"
            android:permission="android.permission.BIND_INCALL_SERVICE">
            <meta-data
                android:name="android.telecom.IN_CALL_SERVICE_UI"
                android:value="true" />
            <intent-filter>
                <action android:name="android.telecom.InCallService" />
            </intent-filter>
        </service>
    </application>
    
  2. Dynamic Permission Request:
    For Android 13+, you need to request the POST_NOTIFICATIONS permission at runtime. Add this code to your Flutter init logic:
    import 'package:permission_handler/permission_handler.dart';
    
    Future<void> requestPermissions() async {
      if (await Permission.notification.isDenied) {
        await Permission.notification.request();
      }
    }
    

iOS

  1. Enable Background Modes:
    Open your iOS project in Xcode, go to your target’s Signing & Capabilities tab, add the Background Modes capability, and check Voice over IP.
  2. Update Info.plist:
    Add these entries to ios/Runner/Info.plist to request necessary permissions:
    <key>NSMicrophoneUsageDescription</key>
    <string>Need microphone access to make and receive calls</string>
    <key>UIBackgroundModes</key>
    <array>
        <string>voip</string>
    </array>
    

Step 3: Flutter Layer Implementation

Initialize the Plugin

Call this when your app starts (e.g., in main.dart after runApp):

import 'package:flutter_callkit_incoming/flutter_callkit_incoming.dart';

void initCallKit() async {
  await FlutterCallkitIncoming.init(
    appName: 'My VoIP App',
    iconName: 'ic_launcher', // Use your app's launcher icon name
    ringtonePath: 'system_ringtone', // Or a custom ringtone path
    // Optional: Customize UI colors, vibration, etc.
  );
}

Trigger an Incoming Call

When your app receives a VoIP push or incoming call signal, call this to show the lock-screen call UI:

void showIncomingCall(String callId, String callerName, String callerNumber) async {
  final callParams = CallKitParams(
    id: callId, // Unique ID for the call
    nameCaller: callerName,
    handle: callerNumber,
    type: 0, // 0 = voice call, 1 = video call
    hasVideo: false,
    duration: 30000, // Ring duration in ms
  );
  await FlutterCallkitIncoming.showCallkitIncoming(callParams);
}

Listen for Call Actions

Set up a listener to handle answer/decline/end events from the lock screen:

void setupCallListeners() {
  FlutterCallkitIncoming.onEvent.listen((event) {
    if (event == null) return;

    switch (event.event) {
      case EventAction.ACTION_CALL_ACCEPT:
        // Handle call acceptance (e.g., connect WebRTC session)
        String callId = event.data['id'];
        acceptCall(callId);
        break;
      case EventAction.ACTION_CALL_DECLINE:
        // Handle call decline (e.g., send busy signal to caller)
        String callId = event.data['id'];
        declineCall(callId);
        break;
      case EventAction.ACTION_CALL_ENDED:
        // Handle call end (e.g., clean up WebRTC resources)
        String callId = event.data['id'];
        endCall(callId);
        break;
      // Handle other events like call timeout, mute, etc. as needed
    }
  });
}

Step 4: Handle VoIP Push Notifications

To receive incoming calls when your app is in the background or terminated, you’ll need to implement VoIP push notifications:

  • For iOS: Use Apple’s VoIP push service (APNs with VoIP payload)
  • For Android: Use Firebase Cloud Messaging (FCM) with high-priority messages

The plugin will automatically wake your app when a VoIP push is received, allowing you to trigger the showIncomingCall method.

Key Notes
  • Android: Using InCallService ensures your call UI is treated as a system-level call, so it will show on the lock screen without extra permissions. Avoid custom lock-screen overlays (they require SYSTEM_ALERT_WINDOW permission which is restricted on newer Android versions).
  • iOS: Apple strictly enforces using CallKit for VoIP calls—any custom lock-screen UI will be blocked. CallKit integrates seamlessly with iOS’s native call log and lock screen.
  • Testing: Always test lock-screen behavior on physical devices (emulators/simulators may not replicate lock-screen UI correctly).

内容的提问来源于stack exchange,提问作者Akas Antony

火山引擎 最新活动