Home > Enterprise >  MethodChannel System Services not available to Activities before onCreate() [Kotlin]
MethodChannel System Services not available to Activities before onCreate() [Kotlin]

Time:03-11

I tried create my custom plugin for Flutter on Kotlin. I accessed the methodChannel and was able to do it, but when I want to use the bluetooth service in the methodChannel i am faicng this error. I did on Kotlin and my code ran correctly. The difference is My kotlin app's class is of type AppCompatActivity() and has onCreate() function. My problem was not solved when I added the onCreate function to my scanner.kt file. I get this error.

> E/MethodChannel#beacon_scanner: Failed to handle method call
>     java.lang.IllegalStateException: System services not available to Activities before onCreate()
>         at android.app.Activity.getSystemService(Activity.java:6868)
>         at com.example.beacon_scanner.BeaconScannerPlugin$onMethodCall$bluetoothAdapter$2.invoke(BeaconScannerPlugin.kt:52)
>         at com.example.beacon_scanner.BeaconScannerPlugin$onMethodCall$bluetoothAdapter$2.invoke(BeaconScannerPlugin.kt:49)
>         at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
>         at com.example.beacon_scanner.BeaconScannerPlugin.onMethodCall$lambda-0(BeaconScannerPlugin.kt:49)
>         at com.example.beacon_scanner.BeaconScannerPlugin.onMethodCall(BeaconScannerPlugin.kt:57)
>         at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
>         at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:296)
>         at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$DartMessenger(DartMessenger.java:320)
>         at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$TsixYUB5E6FpKhMtCSQVHKE89gQ.run(Unknown
> Source:12)
>         at android.os.Handler.handleCallback(Handler.java:938)
>         at android.os.Handler.dispatchMessage(Handler.java:99)
>         at android.os.Looper.loopOnce(Looper.java:201)
>         at android.os.Looper.loop(Looper.java:288)
>         at android.app.ActivityThread.main(ActivityThread.java:7839)
>         at java.lang.reflect.Method.invoke(Native Method)
>         at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
>         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
> E/flutter: [ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled
> Exception: PlatformException(error, System services not available to
> Activities before onCreate(), null, java.lang.IllegalStateException:
> System services not available to Activities before onCreate()
>         at android.app.Activity.getSystemService(Activity.java:6868)
>         at com.example.beacon_scanner.BeaconScannerPlugin$onMethodCall$bluetoothAdapter$2.invoke(BeaconScannerPlugin.kt:52)
>         at com.example.beacon_scanner.BeaconScannerPlugin$onMethodCall$bluetoothAdapter$2.invoke(BeaconScannerPlugin.kt:49)
>         at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
>         at com.example.beacon_scanner.BeaconScannerPlugin.onMethodCall$lambda-0(BeaconScannerPlugin.kt:49)
>         at com.example.beacon_scanner.BeaconScannerPlugin.onMethodCall(BeaconScannerPlugin.kt:57)
>         at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:262)
>         at io.flutter.embedding.engine.dart.DartMessenger.invokeHandler(DartMessenger.java:296)
>         at io.flutter.embedding.engine.dart.DartMessenger.lambda$dispatchMessageToQueue$0$DartMessenger(DartMessenger.java:320)
>         at io.flutter.embedding.engine.dart.-$$Lambda$DartMessenger$TsixYUB5E6FpKhMtCSQVHKE89gQ.run(Unknown
> Source:12)
>         at android.os.Handler.handleCallback(Handler.java:938)
>         at android.os.Handler.dispatchMessage(Handler.java:99)
>         at android.os.Looper.loopOnce(Looper.java:201)
>         at android.os.Looper.loop(Looper.java:288)
>         at android.app.ActivityThread.main(ActivityThread.java:7839)
>         at java.lang.reflect.Method.invoke(Native Method)
>         at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
>         at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
>     )
>     #0      StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:607:7)
>     #1      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:177:18)
>     <asynchronous suspension>
>     #2      BeaconScanner.bluetoothIsActive (package:beacon_scanner/beacon_scanner.dart:14:12)
>     <asynchronous suspension>
>     #3      _MyAppState.getBtStatus (package:beacon_scanner_example/main.dart:50:17)
>     <asynchronous suspension>

And that's my code:

scanner.dart

class BeaconScanner {
  static const MethodChannel _channel = MethodChannel('beacon_scanner');

  static Future<String?> get platformVersion async {
    final String? version = await _channel.invokeMethod('getPlatformVersion');
    return version;
  }
  static Future get bluetoothIsActive async {
    return await _channel.invokeMethod('bluetoothIsActive');
  }
  static Future get sayHello async {
    final btStatus = await _channel.invokeMethod('sayHello');
    return btStatus.toString();
  }
}

scanner.kt

  class BeaconScannerPlugin: FlutterActivity(), FlutterPlugin, MethodCallHandler {
  private lateinit var channel : MethodChannel
  private val bluetoothAdapter: BluetoothAdapter by lazy{
    (getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager).adapter
  }

  companion object {
    private const val BLUETOOTH_PERMISSION_REQUEST_CODE = 9999
  }

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.binaryMessenger, "beacon_scanner")
    channel.setMethodCallHandler(this)

  }

  override fun onMethodCall(@NonNull call: MethodCall, @NonNull result: Result) {
    if (call.method == "getPlatformVersion") {
      result.success("Android ${android.os.Build.VERSION.RELEASE}")
    }
    else if (call.method=="bluetoothIsActive") {

      if(bluetoothAdapter != null){
        if (ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.BLUETOOTH_CONNECT
          ) != PackageManager.PERMISSION_GRANTED
        ) {
          initializeBluetoothOrRequestPermission()
        }
        if(bluetoothAdapter.enable()){
          result.success("bt status is ${bluetoothAdapter.isEnabled}")
          Log.v("Scanner","ENABLED")
        }
        else {
          initializeBluetoothOrRequestPermission()
        }
      }
    }else if (call.method=="sayHello") {
          result.success("bt status is HELLO  YES")
    }
    else {
      result.notImplemented()
    }
  }

  private fun initializeBluetoothOrRequestPermission() {
    val requiredPermissions = listOf(Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN)
    val missingPermissions = requiredPermissions.filter { permission ->
      ActivityCompat.checkSelfPermission(this,permission) != PackageManager.PERMISSION_GRANTED
    }
    if (missingPermissions.isEmpty()) {
    } else {
      ActivityCompat.requestPermissions(this, missingPermissions.toTypedArray(), BLUETOOTH_PERMISSION_REQUEST_CODE)
    }
  }

  override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
    channel.setMethodCallHandler(null)
  }
}

CodePudding user response:

Your BeaconScannerPlugin is an Activity and as the error stacktrace says, it needs to be in the created state before you can use it in getSystemService(Context.BLUETOOTH_SERVICE).

You should change your BeaconScannerPlugin implementation to not depend on FlutterActivity and instead use ActivityAware interface.

ActivityAware will give you an instace of activity that you can use to get the bluetooth service for your plugin.

You can read more on the official flutter webiste

  • Related