androidflutterflutter-method-channel

Flutter: It's possible to send data from Android module to Flutter project via MethodChannel without close Activity(Still in Android Activity)?


I have screens.

  1. StoryScreen (from Flutter)
  2. MainActivity (from Android Activity, extend to FlutterActivity)
  3. MainUnityActivity (from Android Activity, extend to AppCompatActivity)

The actually screen is only two, StoryScreen and MainUnityActivity. MainActivity only for host.

In MainActivity we define intent and method channel.

class MainActivity : FlutterActivity() {
    private val tag = "MAIN"
    private val channel = "NATIVE_EXPERIMENT"

    override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine)
        MethodChannel(flutterEngine.dartExecutor, channel).setMethodCallHandler { call, result ->
            if (call.method.equals("goToUnityActivity")) {
                val arg = call.arguments as Map<String, Any>
                val gameType = arg.getValue("gameType") as String
                val catalogURL = arg.getValue("catalogURL") as String
                goToUnityActivity(gameType, catalogURL)
                result.success(null)
            } else {
                result.notImplemented()
            }
        }
    }

    private fun goToUnityActivity(gameType: String, catalogURL: String) {
        val intent = Intent(this, MainUnityActivity::class.java)
        intent.putExtra("gameType", gameType)
        intent.putExtra("catalogURL", catalogURL)
        startActivityForResult(intent, MainUnityActivity.REQUEST_CODE_FROM_UNITY)
    }

    private fun notifyFlutterBackFromUnity(data: String?) {
        MethodChannel(flutterEngine?.dartExecutor, channel).invokeMethod("backFromUnity", data)
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        if (requestCode == MainUnityActivity.REQUEST_CODE_FROM_UNITY) {
            if (resultCode == MainUnityActivity.RESULT_CODE_BACK_FROM_UNITY) {
                val listOfReport = data!!.getStringExtra("listOfReport")
                Log.i(tag, "/// [MainActivity] back from unity --> $listOfReport")
                notifyFlutterBackFromUnity(listOfReport)
            }
        }
    }
}

If I exit from MainUnityActivity, I can send data from Android to Flutter side, but how if we still in MainUnityActivity but want to send data from Android to Flutter side?

class MainUnityActivity : UnityPlayerActivity() {
    private val tag = "MIDDLEWARE_UNITY"
    private val listOfVehicleNames: MutableList<String> = mutableListOf()

    companion object {
        const val RESULT_CODE_BACK_FROM_UNITY = 110
        const val REQUEST_CODE_FROM_UNITY = 1
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        listOfVehicleNames.clear()
    }

    private fun backFromUnity() {
        Log.i(tag, "/// [MainUnityActivity] BackButtonClick")
        val resultIntent = Intent().apply {
            putExtra("listOfReport", listOfVehicleNames.toString())
        }
        setResult(RESULT_CODE_BACK_FROM_UNITY, resultIntent)
        finish()
    }

    override fun BackButtonClick() {
        Log.i(tag, "/// [MainUnityActivity] BackButtonClick")
        backFromUnity()
    }

    override fun ReportButtonClick() {
        Log.i(tag, "/// [MainUnityActivity] ReportButtonClick")
        showDialog()
    }

    private fun notifyFlutterReportFromUnity() {
        val json = """{"title": "JSON Title", "notes": "JSON Notes"}"""
        Log.i(tag, "/// [MainUnityActivity] YesReportClick :$json")
        listOfVehicleNames.add(json)
        // TODO: I want send data to Flutter without close this activity
    }

    private fun showDialog() {
        val builder = AlertDialog.Builder(this)
        builder.setTitle("Report")
        builder.setMessage("Is there something wrong ?")

        builder.setPositiveButton(
            "Yes"
        ) { _, _ ->
            Toast.makeText(this, "Okay, we're sorry", Toast.LENGTH_SHORT).show()
            notifyFlutterReportFromUnity()
        }

        builder.setNegativeButton(
            "No"
        ) { _, _ ->
            // User click no
        }

        builder.setNeutralButton("Cancel") { _, _ ->
            // User cancelled the dialog
        }
        builder.show()
    }
}

Solution

  • Finally, I fix it using MethodChannel, EventChannel, and BroadcastReceiver.

    Method channel: A named channel for communicating with platform plugins using asynchronous method calls.

    Event Channel: A named channel for communicating with platform plugins using event streams.

    The example project is here: https://github.com/rrifafauzikomara/example_flutter_method_channel