I am working on a Flutter Project where I have to give a call from Flutter to Android(Kotlin) via channel to run some specific task in native android so I used the channel system to achieve this as shown in the below files with the help of https://github.com/liusilong/stack_q/
MainActivity.kt
package com.example.my_flutter_app
import android.os.Build
import android.os.Bundle
import androidx.core.view.WindowCompat
import androidx.annotation.NonNull
import androidx.annotation.Nullable
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.util.Log
import android.app.Activity
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.telephony.SmsManager
class SmsManager
abstract class MainActivity : FlutterActivity(), MethodChannel.MethodCallHandler {
private var channel: MethodChannel? = null
var sendSMS_return: HashMap<String, String?> = HashMap()
protected override fun onCreate(@Nullable savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
channel = MethodChannel(getFlutterEngine()!!.getDartExecutor(), "MY_FLUTTER_APP_CHANNEL")
channel!!.setMethodCallHandler(this)
}
public override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: MethodChannel.Result) {
if (call.method.equals("sendSMS")) {
Log.e("sendSMS", "Function Started Running")
// Handler handler = new Handler(Application.Context.MainLooper);
// handler.post(object : Runnable() {
// Handler(Looper.getMainLooper()).post(object : Runnable() {
runOnUiThread(object : Runnable() { // <--- Error Here
public override fun run() {
val paramsList: HashMap<String, String> = call.arguments as HashMap<String, String>
val sentinelPhoneNumber = paramsList.get("phoneNo")
val message = paramsList.get("msgText")
sendSMS_return.clear()
var SENT = "SMS_SENT"
var DELIVERED = "SMS_DELIVERED"
lateinit var sentPI: PendingIntent
lateinit var deliveredPI: PendingIntent
val delay = 5000 // 1000 milliseconds == 1 second
var isSMSSent = false
var isSMSDelivered = false
sentPI = PendingIntent.getBroadcast(ContextWrapper(applicationContext), 0, Intent(SENT), PendingIntent.FLAG_IMMUTABLE)
deliveredPI = PendingIntent.getBroadcast(ContextWrapper(applicationContext), 0, Intent(DELIVERED), PendingIntent.FLAG_IMMUTABLE)
// if (requestSmsPermission()){
val smsManager = SmsManager.getDefault()
smsManager.sendTextMessage(sentinelPhoneNumber, null, message, sentPI, deliveredPI)
// }
ContextWrapper(applicationContext).registerReceiver(
object : BroadcastReceiver() {
override fun onReceive(arg0: Context, arg1: Intent) {
when (resultCode) {
Activity.RESULT_OK -> isSMSDelivered = true
Activity.RESULT_CANCELED -> { isSMSDelivered = false
}
}
}
}, IntentFilter(DELIVERED)
)
ContextWrapper(applicationContext).registerReceiver(
object : BroadcastReceiver() {
override fun onReceive(arg0: Context, arg1: Intent) {
Log.e("SMS", "SMS Sender In Native Receiver Running")
when (resultCode) {
Activity.RESULT_OK -> {
// Log.e("SMS","SMS sent to book on/off job")
isSMSSent = true
Log.e("SMS", "SMS Sent Successfully.")
//channel.invokeMethod("sendSMS", "SMS Sent Successfully.");
sendSMS_return.put("phone", sentinelPhoneNumber);
sendSMS_return.put("status", "Successful.");
}
SmsManager.RESULT_ERROR_GENERIC_FAILURE -> {
isSMSSent = false
Log.e("SMS", "SMS Not Sent Successfully.")
//channel.invokeMethod("sendSMS", "SMS Not Sent Successfully.");
sendSMS_return.put("phone", sentinelPhoneNumber);
sendSMS_return.put("status", "Not Successful.");
}
SmsManager.RESULT_ERROR_NO_SERVICE -> {
isSMSSent = false
Log.e("SMS", "SMS Not Sent Successfully.")
//channel.invokeMethod("sendSMS", "SMS Not Sent Successfully.");
sendSMS_return.put("phone", sentinelPhoneNumber);
sendSMS_return.put("status", "Not Successful.");
}
SmsManager.RESULT_ERROR_NULL_PDU -> {
isSMSSent = false
Log.e("SMS", "SMS Not Sent Successfully.")
//channel.invokeMethod("sendSMS", "SMS Not Sent Successfully.");
sendSMS_return.put("phone", sentinelPhoneNumber);
sendSMS_return.put("status", "Not Successful.");
}
SmsManager.RESULT_ERROR_RADIO_OFF -> {
isSMSSent = false
Log.e("SMS", "SMS Not Sent Successfully.")
//channel.invokeMethod("sendSMS", "SMS Not Sent Successfully.");
sendSMS_return.put("phone", sentinelPhoneNumber);
sendSMS_return.put("status", "Not Successful.");
}
else -> {
Log.e("SMS", "SMS Not Sent Successfully.")
//_channel.invokeMethod("sendSMS", "SMS Not Sent Successfully.");
sendSMS_return.put("phone", sentinelPhoneNumber);
sendSMS_return.put("status", "Not Successful.");
}
}
// Send SMS Via Native Code
// Send Data To Flutter(Dart) via HashMap
channel.invokeMethod("sendSMS", sendSMS_return);
Log.e("sendSMS_return", Gson().toJson(sendSMS_return))
// Send Data To Flutter(Dart) via HashMap
}
}, IntentFilter(SENT)
)
// Invoke Return Dart Method
channel!!.invokeMethod("sendSMS", sendSMS_return);
}
})
}
}
}
And...
andriod_service.dart
import 'package:flutter/services.dart';
class AndroidService {
AndroidService() {
_channel.setMethodCallHandler(_methodCallHandler);
}
final MethodChannel _channel = const MethodChannel('MY_FLUTTER_APP_CHANNEL');
Function(String, String)? _loginSuccessCallback;
Future<void> sendSMS(String phoneNo, String msgText, {Function(String, String)? callback}) async {
_loginSuccessCallback = callback;
var params = {'phoneNo': phoneNo, 'msgText': msgText};
// Call The Native Method 'sendSMS'
await _channel.invokeMethod('sendSMS', params);
}
Future<dynamic> _methodCallHandler(MethodCall call) async {
String method = call.method;
// Get Return From The Native Method 'sendSMS'
if (method == 'sendSMS') {
if (_loginSuccessCallback != null) {
final map = call.arguments;
_loginSuccessCallback?.call(map['key'] as String, map['value'] as String);
}
}
}
}
And I call this in my flutter app as...
final AndroidService androidService = AndroidService();
androidService.sendSMS(phoneNo, msg, callback: (String key, String value) {
print("MY_FLUTTER_APP_CHANNEL [key: $key, value: $value]");
});
But I am getting error in MainActivity.kt
as c: /Users/MY_PC/AndroidStudioProjects/my_flutter_app/android/app/src/main/kotlin/com/example/retrofit_mine/MainActivity.kt: (263, 46): This class does not have a constructor
that I commented on MainActivity.kt
code shared above.
So how to fix this...???
CodePudding user response:
You just need to remove the parenthesis after Runnable interface:
From this:
runOnUiThread(object : Runnable() <--- remove this {
To this:
runOnUiThread(object : Runnable {
CodePudding user response:
The other answer shows the problem with your code. Just want to mention, you can simplify the syntax in this case, since Runnable is a SAM interface (only has one method).
This
runOnUiThread(object : Runnable {
public override fun run() {
//...
}
})
can be replaced with:
runOnUiThread {
//...
}
to accomplish exactly the same thing with less nesting and brackets to keep track of.