uni-app 跳转Android原生界面(Activity),并传值交互
应大家的要求,我研究了一下相互传值操作
一、uni-app 跳转Android原生界面(Activity)并传值
- 前端传值操作
<!DOCTYPE html><html><head> <meta charset="utf-8"/></head><body><input type="button" value="js start native Activity" onclick="jsCallNativeActivity()"/></body><script type="text/javascript"> function jsCallNativeActivity(){ //获取宿主上下文 var main = plus.android.runtimeMainActivity(); //通过反射获取Android的Intent对象 var Intent = plus.android.importClass("android.content.Intent"); //通过宿主上下文创建 intent var intent = new Intent(main.getIntent()); //设置要开启的Activity包类路径 com.HBuilder.integrate.MainActivity换掉你自己的界面 intent.setClassName(main, "com.HBuilder.integrate.MainActivity"); //开启新的任务栈 (跨进程) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //向原生界面传值操作 intent.putExtra("uni_key","来自uniapp的值"); //开启新的界面 main.startActivity(intent); }</script></html>
做Android的都知道intent.putExtra(key,value)就是通过Intent进行不同组件之间传值操作,前端开发人员我建议直接封装成json传值,intent.putExtra(“uni_json_key”,"{key,“value1”}");
- Android端接收传值
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent mIntent = getIntent(); if (mIntent!=null){ //获取Intent,通过key获取对应的值 String uniValue = mIntent.getStringExtra("uni_key"); Toast.makeText(this, "uniValue="+uniValue, Toast.LENGTH_SHORT).show(); } }}
效果如下:
二、uni-app 跳转Android原生界面(Activity)并传值,并返回uni-app时带返回值
- uni-app开启android 原生界面,并请求返回值
function jsCallNativeActivity(){ //获取宿主上下文 var main = plus.android.runtimeMainActivity(); //通过反射获取Android的Intent对象 var Intent = plus.android.importClass("android.content.Intent"); //通过宿主上下文创建 intent var intent = new Intent(main.getIntent()); //设置要开启的Activity包类路径 com.HBuilder.integrate.MainActivity换掉你自己的界面 intent.setClassName(main, "com.HBuilder.integrate.MainActivity"); //开启新的任务栈 (跨进程) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //uni向android原生界面传值 intent.putExtra("uni_key","来自uniapp的值"); //请求码保证了,开始的新界面和返回的是同一个操作 var CODE_REQUEST=1000 //采用startActivityForResult开启新的界面,当界面关闭时可以处理返回结果, CODE_REQUEST请求码是唯一标识 main.startActivityForResult(intent,CODE_REQUEST); //设置原生界面返回后的回调操作 main.onActivityResult = function(requestCode, resultCode, data) { if (requestCode == CODE_REQUEST) { alert(requestCode); //这个是正确的 1000 alert(resultCode); //始终都是0 alert(data); //弹出 undefined } } }
- Android端点击按钮,关闭原生界面,返回值
public void backValue(View view) { Intent mIntent = new Intent(); mIntent.putExtra("Native_RESULT_Key", "来自原生界面的返回值"); setResult(Activity.RESULT_OK, mIntent); finish(); }
上面一顿操作后,理论上应该是可以返回值的,但是实际上除了requestCode是正确的,其他的值都是错误的,为什么呢?我跟了安卓这边的官方demo源码,发现有bug,onActivityResult方法居然在开启新界面的时候就被调用,在返回的时候设置 setResult(Activity.RESULT_OK, mIntent);后onActivityResult压根就没有走,所以这样resultCode和data都没有被正常赋值,如下图log
可以看到官方在这里挖了一个坑,多少人跳了进去,为什么他的生命周期方法会调用错乱呢?uni-app的demo是这么写的,用一个代理类去处理所有的事件操作
只能看Android的官方源码
也就是在我们开启原生的activity重新开始交互时,将在onResume()之前调用onActivityResult将上个界面的值返回,现在onActivityResult没有执行,说明uni-app在某些地方做了方法拦截,导致Android生命周期方法回调异常;所以这个问题需要uni-app官方处理,把Android的生命周期理顺
我个人提出的解决方案就是采用EventBus去手动调用SDK_WebApp中的onActivityResult,具体如下
1、app.gradle 依赖 implementation 'org.greenrobot:eventbus:3.0.0'
2、创建DataSynEvent
public class DataSynEvent { public int requestCode; public int resultCode; public Intent data; public DataSynEvent(int requestCode, int resultCode, Intent data) { this.requestCode = requestCode; this.resultCode = resultCode; this.data = data; }}
3、SDK_WebApp.java修改
public class SDK_WebApp extends Activity implements IActivityDelegate { private static final String TAG = "SDK_WebApp"; .... @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); .... //注册EventBus EventBus.getDefault().register(this); } @Override protected void onDestroy() { super.onDestroy(); Log.d(TAG, "onDestroy: "); mEntryProxy.onStop(this); //解绑EventBus EventBus.getDefault().unregister(this); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { Log.d(TAG, "onActivityResult: " + data + ",requestCode=" + requestCode + ",resultCode=" + resultCode); super.onActivityResult(requestCode, resultCode, data); if (data!=null){ //第一次启动的时候调用这个方法data肯定为null.所以减少调用次数 mEntryProxy.onActivityExecute(this, SysEventType.onActivityResult, new Object[]{requestCode, resultCode, data}); } } @Subscribe(threadMode = ThreadMode.MAIN) public void onDataSynEvent(DataSynEvent event) { Log.d(TAG, "onDataSynEvent: "); //手动调用 onActivityResult(event.requestCode, event.resultCode, event.data); }}
4、修改原生界面的返回方法
public void backValue(View view) { Intent data= new Intent(); data.putExtra("Native_RESULT_Key", "来自原生界面的返回值"); //用EventBus替换setResult(Activity.RESULT_OK,data); EventBus.getDefault().post(new DataSynEvent(1000,Activity.RESULT_OK,data)); finish(); }
5、修改前端的接收方法
function jsCallNativeActivity(){ //获取宿主上下文 var main = plus.android.runtimeMainActivity(); //通过反射获取Android的Intent对象 var Intent = plus.android.importClass("android.content.Intent"); //通过宿主上下文创建 intent var intent = new Intent(main.getIntent()); //设置要开启的Activity包类路径 com.HBuilder.integrate.MainActivity换掉你自己的界面 intent.setClassName(main, "com.HBuilder.integrate.MainActivity"); //uni向android原生界面传值 intent.putExtra("uni_key","来自uniapp的值"); //开启新的任务栈 (跨进程) intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //请求码保证了,开始的新界面和返回的是同一个操作 var CODE_REQUEST=1000 //采用startActivityForResult开启新的界面,当界面关闭时可以处理返回结果, CODE_REQUEST请求码是唯一标识 main.startActivityForResult(intent,CODE_REQUEST); //设置原生界面返回后的回调操作 main.onActivityResult = function(requestCode, resultCode, data) { if (requestCode == CODE_REQUEST) { alert(requestCode); //这个是正确的 1000 alert(resultCode); //这个是正确的 -1 alert(data.getStringExtra("Native_RESULT_Key")); //弹出 来自原生界面的返回值 } } }
6、上效果
*看到官方论坛有人问main
是啥东西,其实就是通过反射获取的宿主Activity的一个实例对象,也就是com.HBuilder.integrate.SDK_WebApp
*
2020年5月12日补充
关于通信,uni-app官方在2020年四月底给出了相关api 宿主 App 向小程序发送事件
- Android 平台API
DCUniMPSDK.getInstance().sendUniMPEvent(event, data)
- 参数说明
参数 | 类型 | 必填 | 说明 |
---|---|---|---|
event | String | yes | 触发事件的event |
data | String或者JSON | yes | 事件携带的参数 |
- 返回值
类型 | 说明 |
---|---|
boolean | true表示事件通知成功。false表示失败。可通过log查看。 |
更多相关文章
- 动画·界面
- Android中弹出输入法界面不影响APP界面解决办法
- Android activity 单手操作 滑动关闭
- android通过USB的MTP模式下,禁止用户在根目录有任何操作(重命名 删
- Android中main.xml界面参数笔记
- 我的Android之旅——UI界面六大布局之认识布局(一)
- Android中欢迎界面背景图片放大效果
- Android启动界面实现
- android EditText 监听复制粘贴等操作