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

273

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

Share:
273
Baran Gungor
Author by

Baran Gungor

Updated on January 03, 2023

Comments

  • Baran Gungor
    Baran Gungor over 1 year

    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)
      }
    }