背景
最近一直在考虑Flutter如何处理由原生页面处理后返回的结果,比如:startActivityForResult,需要处理的结果必须在onActivityResult方法处理,但是Dart代码中又要接收到该值。经过多番查看资料,终于找到了相应的办法。
相关代码
创建一个插件库,编写一个叫RouterPlugin的项目。注意代码中的几个重要的接口:PluginRegistry.ActivityResultListener,该类需要实现onActivityResult方法,用于处理相应的返回处理。
-
插件类中保存MethodCall、Result的实例,用于处理相关的结果。
class RouterPlugin private constructor(private val registrar: Registrar) : MethodCallHandler, PluginRegistry.ActivityResultListener { companion object { @JvmStatic private val TAG = RouterPlugin::class.java.simpleName @JvmStatic fun registerWith(registrar: Registrar): Unit { val instance = RouterPlugin(registrar) val channel = MethodChannel(registrar.messenger(), "router_plugin") registrar.addActivityResultListener(instance) channel.setMethodCallHandler(instance) } } private var methodCall: MethodCall? = null private var pendingResult: Result? = null private var requestCode: Int = 0 override fun onMethodCall(call: MethodCall, result: Result): Unit { if (this.pendingResult != null) { Log.e(TAG, "RouterPlugin is already active.") return } val activity = registrar.activity() if (activity == null) { Log.e(TAG, "RouterPlugin requires a foreground activity.") return } this.methodCall = call this.pendingResult = result val activityClassName = if (!call.hasArgument("activity")) null else call.argument<String>("activity") if (activityClassName.isNullOrEmpty()) { Log.e(TAG, "RouterPlugin requires a activity class name.") return } val arguments = if (!call.hasArgument("arguments")) null else call.argument<Map<String, Any>?>("arguments") when (call.method) { "startActivity" -> { activity.startActivity(getActivityIntent(activity, activityClassName!!, arguments)) result.success(null) this.methodCall = null this.pendingResult = null } "startActivityForResult" -> { val requestCode = if (!call.hasArgument("requestCode")) -1 else call.argument("requestCode") if (requestCode == -1) { Log.e(TAG, "RequestCode cannot be null") return } this.requestCode = requestCode activity.startActivityForResult(getActivityIntent(activity, activityClassName!!, arguments), requestCode) } } } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean { if (requestCode == this.requestCode) { if (resultCode == Activity.RESULT_OK) { val ret: MutableMap<String, Any> = mutableMapOf() data?.extras?.keySet()?.forEach { ret[it] = data.extras[it] } println("---------->信息:$ret") this.pendingResult?.success(if (ret.isEmpty()) null else ret) } this.methodCall = null this.pendingResult = null this.requestCode = 0 return true } return false } private fun getActivityIntent(context: Context, activityClassName: String, params: Map<String, Any>? = null): Intent { val intent = Intent(context, Class.forName(activityClassName)) with(intent) { params?.forEach { key, value -> when (value) { is Char -> putExtra(key, value) is Short -> putExtra(key, value) is Int -> putExtra(key, value) is Long -> putExtra(key, value) is Float -> putExtra(key, value) is Double -> putExtra(key, value) is Boolean -> putExtra(key, value) is String -> putExtra(key, value) is CharArray -> putExtra(key, value) is ShortArray -> putExtra(key, value) is IntArray -> putExtra(key, value) is LongArray -> putExtra(key, value) is FloatArray -> putExtra(key, value) is DoubleArray -> putExtra(key, value) is BooleanArray -> putExtra(key, value) is Parcelable -> putExtra(key, value) else -> putExtra(key, Gson().toJson(value)) //复杂类型会被转换成JSON-String } } } return intent } }
-
对应的dart代码[RouterPlugin.dart]
class RouterPlugin { static const MethodChannel _channel = const MethodChannel('router_plugin'); static void startActivity(String activityClassName, [Map<String, dynamic> arguments]) => _channel.invokeMethod("startActivity", { "activity": activityClassName, "arguments": arguments }); static Future<dynamic> startActivityForResult(String activityClassName, int requestCode, [Map<String, dynamic> arguments]) => _channel.invokeMethod("startActivityForResult", { "activity": activityClassName, "requestCode": requestCode, "arguments": arguments }); }
-
主项目添加一个Activity,叫做HeloActivity,并编写以下代码
class HeloActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_helo) } override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { if (keyCode == KeyEvent.KEYCODE_BACK && event?.action == KeyEvent.ACTION_DOWN) { val data = Intent() data.putExtra("name", "谢尔顿") data.putExtra("age", 8) setResult(Activity.RESULT_OK, data) this.finish() return true } return super.onKeyDown(keyCode, event) } }
-
测试代码[main.dart]
void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( title: 'Flutter Demo', theme: new ThemeData( primarySwatch: Colors.blue, ), home: new MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => new _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { String backMessage; //返回信息 _incrementCounter() async { var value = await RouterPlugin.startActivityForResult( "com.mrper.flutterapp.HeloActivity", 200); //启动一个原生页面 setState(() { backMessage = value.toString(); }); } @override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text(widget.title), ), body: new Center( child: new Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ new Text( '接收startActivityForResult返回的信息:', ), new Text( '$backMessage', style: Theme.of(context).textTheme.display1, ), ], ), ), floatingActionButton: new FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: new Icon(Icons.add), ), ); } }
结语
现目前能从Flutter跳转到原生UI了,但是如何从原生UI跳转到Flutter的UI,现目前也还没找到相应的策略,纠结!