Shivang Srivastava
Shivang Srivastava

Reputation: 13

MissingPluginException for MethodChannel in Flutter on Android

I’m encountering a MissingPluginException when trying to use MethodChannel in Flutter to send SMS in my Android app. Even though I’ve implemented the native code correctly, the app throws this error at runtime.

Error

E/flutter (10616): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: MissingPluginException(No implementation found for method sendSMS on channel channel_name)
E/flutter (10616): #0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:332:7)
E/flutter (10616): <asynchronous suspension>
E/flutter (10616): #1      SmsService.sendSms (package:muteify/services/sms_service.dart:8:30)
E/flutter (10616): <asynchronous suspension>
E/flutter (10616): #2      phoneStateBackgroundCallbackHandler (package:muteify/services/phone_state_bg_helper.dart:16:19)
E/flutter (10616): <asynchronous suspension>

Dart Code (Flutter side):

import 'package:flutter/services.dart';

const platform = MethodChannel('channel_name');

class SmsService {
  Future<String?> sendSms(String phone, String message) async {
    try {
      final String? result = await platform.invokeMethod<String?>('sendSMS', {
        'phone': phone,
        'message': message,
      });
      print("SMS result:  $result");
      return result;
    } on PlatformException catch (e) {
      return "Failed to send SMS: '${e.message}'.";
    }
  }
}

MainActivity.kt (Android side):

@file:Suppress("DEPRECATION")

package com.example.muteify

import android.telephony.SmsManager
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.Result

class MainActivity : FlutterActivity() {
    private val channel = "channel_name"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        super.configureFlutterEngine(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor.binaryMessenger, channel).setMethodCallHandler { call, result ->
            if (call.method=="sendSMS"){
                val customerPhone = call.argument<String>("phone")
                val customerMessage = call.argument<String>("message")
                if (customerPhone != null && customerMessage != null) {
                    sendSMS(customerPhone, customerMessage, result)
                } else {
                    result.error("INVALID_ARGUMENT", "Phone number or message is null", null)
                }
            }
            else {
                result.notImplemented()
            }
        }
    }

    private fun sendSMS(phone: String, message: String, result: Result) {
        return try {
            val smsManager: SmsManager = SmsManager.getDefault()
            smsManager.sendTextMessage(phone, null, message, null, null)
            result.success("SMS sent successfully")
        } catch (e: Exception) {
            result.error("SMS_SEND_FAILED", "Failed to send SMS: ${e.message}", null)
        }
    }
}

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CALL_LOG" />
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
    <uses-permission android:name="android.permission.USE_EXACT_ALARM" />
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
    <uses-permission android:name="android.permission.WRITE_CONTACTS"/>
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <application
        android:label="muteify"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:taskAffinity=""
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize">
            <!-- Specifies an Android theme to apply to this Activity as soon as
                 the Android process has started. This theme is visible to the user
                 while the Flutter UI initializes. After that, this theme continues
                 to determine the Window background behind the Flutter UI. -->
            <meta-data
              android:name="io.flutter.embedding.android.NormalTheme"
              android:resource="@style/NormalTheme"
              />
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <receiver android:name="me.sodipto.phone_state_background.PhoneStateBackgroundServiceReceiver"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE" />
            </intent-filter>
        </receiver>
        <!-- Don't delete the meta-data below.
             This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
        <meta-data
            android:name="flutterEmbedding"
            android:value="2" />
    </application>
    <!-- Required to query activities that can process text, see:
         https://developer.android.com/training/package-visibility and
         https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.

         In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
    <queries>
        <intent>
            <action android:name="android.intent.action.PROCESS_TEXT"/>
            <data android:mimeType="text/plain"/>
        </intent>
    </queries>
</manifest>

What I’ve Tried:

Expected Behavior:

The app should successfully send an SMS via MethodChannel, even when the app is running in the background, without throwing the MissingPluginException error.

Flutter Doctor:

Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.24.3, on Pop!_OS 22.04 LTS
    6.9.3-76060903-generic, locale en_US.UTF-8)
[✓] Android toolchain - develop for Android devices (Android SDK version 35.0.0)
[✓] Chrome - develop for the web
[✓] Linux toolchain - develop for Linux desktop
[✓] Android Studio (version 2024.1)
[✓] VS Code (version 1.93.1)
[✓] Connected device (3 available)
[✓] Network resources

• No issues found!

Question:

What could be causing this MissingPluginException and how can I resolve it? Is there something I missed in the method channel configuration or manifest setup?

Upvotes: 0

Views: 161

Answers (1)

Zubair Soomro
Zubair Soomro

Reputation: 180

You need to use .equals inside of == operator in kotlin this is basic programming so i want be getting into it, there is alot which explains when to use == or .equals.

if (call.method.equals("sendSMS")){
            val customerPhone = call.argument<String>("phone")
            val customerMessage = call.argument<String>("message")
            if (customerPhone != null && customerMessage != null) {
                sendSMS(customerPhone, customerMessage, result)
            } else {
                result.error("INVALID_ARGUMENT", "Phone number or message is null", null)
            }
        }
        else {
            result.notImplemented()
        }

Upvotes: 0

Related Questions