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查看。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章