How to get Activity and Context in Flutter plugin

Depends on flutter document in Create-Flutter-Plugin, Follow these steps:

1- Import ActivityAware:

import io.flutter.embedding.engine.plugins.activity.ActivityAware

2- implement ActivityAware in your class:

public class ClassName: FlutterPlugin, MethodCallHandler, ActivityAware { 

3- Define lateinit variables to use it class:

private lateinit var context: Context
private lateinit var activity: Activity

4- Add these functions:

override fun onDetachedFromActivity() {
    TODO("Not yet implemented")
}

override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
    TODO("Not yet implemented")
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
    activity = binding.activity;
}

override fun onDetachedFromActivityForConfigChanges() {
    TODO("Not yet implemented")
}

5- Add this line in onAttachedToEngine function:

context = flutterPluginBinding.applicationContext

You can see this full code for more understanding:

package com.example.flutter_plugin_name

import android.app.Activity
import android.content.Context
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar


public class FlutterPluginName: FlutterPlugin, MethodCallHandler, ActivityAware {
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private lateinit var channel : MethodChannel

    private lateinit var context: Context
    private lateinit var activity: Activity

  override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
    channel = MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "flutter_plugin_name")
    channel.setMethodCallHandler(this);
    context = flutterPluginBinding.applicationContext
  }



  // This static function is optional and equivalent to onAttachedToEngine. It supports the old
  // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
  // plugin registration via this function while apps migrate to use the new Android APIs
  // post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
  //
  // It is encouraged to share logic between onAttachedToEngine and registerWith to keep
  // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
  // depending on the user's project. onAttachedToEngine or registerWith must both be defined
  // in the same class.
  companion object {
    @JvmStatic
    fun registerWith(registrar: Registrar) {
      val channel = MethodChannel(registrar.messenger(), "flutter_plugin_name")
      channel.setMethodCallHandler(FlutterMapboxTurnByTurnPlugin())
    }
  }

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

    else {
      result.notImplemented()
    }
  }

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

    override fun onDetachedFromActivity() {
        TODO("Not yet implemented")
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        TODO("Not yet implemented")
    }

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        activity = binding.activity;
    }

    override fun onDetachedFromActivityForConfigChanges() {
        TODO("Not yet implemented")
    }
}

Looking at BatteryPlugin source code (Since it is from Flutter team, I think this is the correct way):

  private Context mContext; // Instance variable for context

  // ....

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    onAttach(flutterPluginBinding.getApplicationContext(),flutterPluginBinding.getBinaryMessenger());  // <- this is the line we need here, a new method call
    final MethodChannel channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), "com.myplugin/my_plugin");
    channel.setMethodCallHandler(new MyPlugin());
  }

 //here is the implementation of that new method
 private void onAttachedToEngine(Context applicationContext, BinaryMessenger messenger) {
     this.mContext = applicationContext;
     methodChannel = new MethodChannel(messenger, "com.myplugin/my_plugin");
     methodChannel.setMethodCallHandler(this);
 }

 // ....

And here is how Google Software Engineer from Flutter team recommend to use Activity:

On a simple MethodChannel with a annonymous MethodCallHandler:

public class MyPlugin {
  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_channel");
    final Activity activity = registrar.activity();
    channel.setMethodCallHandler(new MethodCallHandler() {
      @Override
      public void onMethodCall(MethodCall call, Result result) {
        // use activity here
      }
    });
  }
}

By implementing your class with MethodCallHandler:

Registrar provides when registration time activity() accessor. We can use this Activity by implementing our plugin constructor and store it in a field for use in the onMethodCall method:

public class MyPlugin implements MethodCallHandler {
  private final Activity activity;

  public static void registerWith(Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "my_channel");
    channel.setMethodCallHandler(new MyPlugin(registrar.activity()));
  }

  private MyPlugin(Activity activity) {
    this.activity = activity;
  }

  @Override
  public void onMethodCall(MethodCall call, Result result) {
    // use activity here
  }
}

I use PlatformViewFactory, I can get Activity, Activity's context and Application context from Registrar.

class YourPlatformViewFactory(private val registrar: PluginRegistry.Registrar) : PlatformViewFactory(StandardMessageCodec.INSTANCE) {
    override fun create(context: Context?, id: Int, args: Any?): PlatformView {
        val activityContext = registrar.activeContext()
        val appContext = registrar.context()
        val activity = registrar.activity()
        return YourPlatformView()
    }
}

Add this abstract class to your project:

import android.app.Activity
import android.content.Context
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.MethodChannel
import java.lang.ref.WeakReference

abstract class ContextAwarePlugin : FlutterPlugin, ActivityAware, MethodChannel.MethodCallHandler {

    abstract val pluginName: String

    private lateinit var channel : MethodChannel

    protected val activity get() = activityReference.get()
    protected val applicationContext get() =
        contextReference.get() ?: activity?.applicationContext

    private var activityReference = WeakReference<Activity>(null)
    private var contextReference = WeakReference<Context>(null)

    override fun onAttachedToActivity(binding: ActivityPluginBinding) {
        activityReference = WeakReference(binding.activity)
    }

    override fun onDetachedFromActivityForConfigChanges() {
        activityReference.clear()
    }

    override fun onReattachedToActivityForConfigChanges(binding: ActivityPluginBinding) {
        activityReference = WeakReference(binding.activity)
    }

    override fun onDetachedFromActivity() {
        activityReference.clear()
    }

    override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
        channel = MethodChannel(flutterPluginBinding.binaryMessenger, pluginName)
        channel.setMethodCallHandler(this)

        contextReference = WeakReference(flutterPluginBinding.applicationContext)
    }

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

Use it this way in your plugin:

class MyPlugin: ContextAwarePlugin() {

  override val pluginName: String = "my-plugin"

  override fun onMethodCall(call: MethodCall, result: Result) {
    applicationContext //Do something
    activity //Do something
  }
}