1. 程式人生 > >React-Native之Android:原生介面與React介面的相互呼叫

React-Native之Android:原生介面與React介面的相互呼叫

這裡原生介面是指用佈局檔案實現或Java程式碼實現view的Activity,React介面是指用ReactJS實現的介面的Activity。

從某種角度看,React只是充當了Android裡的view層,因此原生介面與React介面的相互呼叫及資料傳遞同原生介面之間的互動基本是一致的。

下面是我對兩種介面的相互呼叫和資料傳遞的一種實現嘗試,不一定是最有效率或最佳的,純當練習和探索而已。

一、原生介面呼叫React介面

1.只是啟動React介面的話很簡單,同原生介面間的啟動一樣,直接用startActivity即可。

2.在啟動React介面時傳遞資料給React介面。

先來捋下思路,原生介面啟動是沒問題的,同原生一樣;關鍵是React介面如何獲取到傳遞過來的值:從前面的學習中我們知道原生模組是有很大自由度的,只要能得到React介面所在activity就可以順著得到傳遞的來的intent,而JS端想得到資料就要利用回撥函數了。

接下來是實現思路,從後往前來:首先先要按之前構建原生模組的步驟一步步來構建我們這次需要的功

  1. publicclass MyIntentModuleextendsReactContextBaseJavaModule  
  2.     @ReactMethod
  3.     publicvoid getDataFromIntent(Callback successBack,Callback erroBack){  
  4.     try{  
  5.         Activity currentActivity = getCurrentActivity();  
  6.         String result = currentActivity.getIntent().getStringExtra("result"
    );//會有對應資料放入
  7.         if (TextUtils.isEmpty(result)){  
  8.             result = "No Data";  
  9.     }  
  10.     successBack.invoke(result);  
  11.     }catch (Exception e){  
  12.         erroBack.invoke(e.getMessage());  
  13.     }  
  14. }  
  15. `  
  16. ```  
  17. publicclassMyReactPackageimplementsReactPackage   
  18.     @Override
  19.     public List createNativeModules(ReactApplicationContext reactContext) {  
  20.         return Arrays.asList(  
  21.         new MyIntentModule(reactContext)  
  22.     );  
  23. }  
  24. ```  
  25. ```  
  26. publicclassMyReactActivityextendsReactActivity  
  27.     @Override
  28.     protectedListgetPackages(){  
  29.         returnArrays.asList(  
  30.         newMainReactPackage(),  
  31.         newMyReactPackage()  
  32.     );  
  33. }  
  34. ```  
  35. 在JS端配置相應程式碼  
  36. .......  
  37. classmyreactactivity extendsReact.Component{  
  38.     constructor(props){  
  39.     super(props);//這一句不能省略,照抄即可
  40.     this.state={  
  41.         TEXT:'Input Text',//這裡放你自己定義的state變數及初始值
  42.     };  
  43. }  
  44.     render(){  
  45.     return(  
  46.     style={{height:40,borderColor:'gray',borderWidth:1,}}  
  47.     onChangeText={(text)=>this.setState({text})}  
  48.     value={this.state.TEXT}/>  
  49.     )  
  50. }  
  51.     componentDidMount(){   //這是React的生命週期函式,會在介面載入完成後執行一次
  52.     React.NativeModules.MyIntentModule.getDataFromIntent(  
  53.     (successMsg)=>{  
  54.     this.setState({TEXT:successMsg,}); //狀態改變的話重新繪製介面
  55. },  
  56. (erroMsg)=>{alert(erroMsg)}  
  57. );  
  58. }  
  59. }  
  60. .......  
  61. 最後在原生介面將資料存放在intent裡,然後用startActivity啟動;  
  62. Intentintent=newIntent(this,MyReactActivity.class);  
  63. intent.putExtra("result","haha");  
  64. startActivity(intent,10);  
  65. 3.原生介面啟動React介面後等待回撥資料。  
  66. 在原生應用裡是通過intent來傳遞資料,有 startActivityForResult 和onAcitvityResult來滿足啟動和回撥,回傳資料的用setResult設定intent。  
  67. 同上面一樣,由於可以得到當前activity,這些問題也迎刃而解了。  
  68. 先在MyIntentModule裡新增方法  
  69. @ReactMethod
  70. publicvoidfinishActivity(Stringresult){  
  71.     ActivitycurrentActivity=getCurrentActivity();  
  72.     Intentintent=newIntent();  
  73.     intent.putExtra("result",result);  
  74.     currentActivity.setResult(11,intent);  
  75.     currentActivity.finish();  
  76. }  
  77. 在JS端配置相應程式碼  
  78. React.NativeModules.MyIntentModule.finishActivity(this.state.TEXT);  
  79. 至於原生介面裡程式碼就略去不寫了,會安卓的人都可以寫出來了。  
  80. 二、React介面呼叫原生介面  
  81. 1.只是啟動原生介面  
  82. 安卓中啟動activity有隱式和顯式,這裡只考慮顯示啟動。顯式啟動需要指定目的activity的類,而我們雖然可以定製原生模組供JS呼叫,但並不能直接指定類或位元組碼為引數。一些特殊的情況下時可以用swtich的思路來解決,適用性更好的方法有沒有呢,如何用允許的引數來得到目的類呢。這裡就要要到反射了。  
  83. 先在MyIntentModule裡新增方法  
  84. @ReactMethod
  85. publicvoidstartActivityByString(StringactivityName){  
  86.     try{  
  87.         ActivitycurrentActivity=getCurrentActivity();  
  88.         if(null!=currentActivity){  
  89.             ClassaimActivity=Class.forName(activityName);  
  90.             Intentintent=newIntent(currentActivity,aimActivity);  
  91.             currentActivity.startActivity(intent);  
  92.         }  
  93.     }catch(Exceptione){  
  94.         thrownewJSApplicationIllegalArgumentException(  
  95.         "Could not open the activity : "+e.getMessage());  
  96.     }  
  97. }  
  98. 在JS裡呼叫  
  99. React.NativeModules.MyIntentModule..startActivityByString("com.example.SecondActivity")  
  100. 2.啟動原生介面並傳遞進資料  
  101. 這和上面相比就是多了幾個引數的事,沒有啥好講的,只是只能傳遞基本資料型別的引數。要想做到和原生一樣在intent裡任意傳遞基本資料和類還做不到,而且要想自己用的方便一點的話還需要再考慮封裝模組方法,在此不贅述。  
  102. 3.React介面啟動原生介面後等待回撥資料  
  103. 啟動原生介面是同2一樣的,問題在於原生介面返回的資料是在React介面所在Activity的onActvityResult裡接受的,而JS端接受原生模組傳回的資料是通過呼叫原生模組方法時設定的回撥函式接受到的,如何將onActivityResult裡的資料實時傳遞到原生模組裡方法設定的回撥函式裡呢?如果不考慮這些回撥只是把資料存在變數或者檔案裡,用一個類似messageQueue的思路應該可以解決,不過那樣需要可能效率上不太高,我們自己實現起來也不太方便。幸運的是在Java裡已經有BlockingQueue了。  
  104. 先在MyReactActivity裡新增程式碼  
  105. publicstatic ArrayBlockingQueue myBlockingQueue = new ArrayBlockingQueue(1);  
  106.     @Override
  107.     publicvoidonActivityResult(intrequestCode,intresultCode,Intentdata){  
  108.         super.onActivityResult(requestCode,resultCode,data);  
  109.         if(resultCode==RESULT_OK&&requestCode==100){  
  110.             Stringresult=data.getStringExtra("result");  
  111.         if(!TextUtils.isEmpty(result)){  
  112.             MyConstants.myBlockingQueue.add(result);  
  113.         }else{  
  114.             MyConstants.myBlockingQueue.add("無資料傳回");  
  115.     }  
  116. }  
  117. }else{  
  118. MyConstants.myBlockingQueue.add("沒有");  
  119. }  
  120. }  
  121. 在MyIntentModule裡新增方法  
  122. @ReactMethod
  123. publicvoidstartActivityForResult(StringactivityName,intrequestCode,CallbacksuccessCallback,CallbackerroCallback){  
  124.     try{  
  125.         ActivitycurrentActivity=getCurrentActivity();  
  126.         if(null!=currentActivity){  
  127.             ClassaimActivity=Class.forName(activityName);  
  128.             Intentintent=newIntent(currentActivity,aimActivity);  
  129.             currentActivity.startActivityForResult(intent,requestCode);  
  130.             Stringresult=MyConstants.myBlockingQueue.take();  
  131.             successCallback.invoke(result);  
  132.         }  
  133.         }catch(Exceptione){  
  134.             erroCallback.invoke(e.getMessage());  
  135.             thrownewJSApplicationIllegalArgumentException(  
  136.             "Could not open the activity : "+e.getMessage());  
  137.     }  
  138. }  
  139. 在JS端呼叫  
  140. React.NativeModules.MyIntentModule.startActivityForResult(  
  141.     "com.example.SecondActivity",100,  
  142.     (successMsg)=>{  
  143.         this.setState({TEXT:successMsg,});  
  144.     },  
  145.     (erroMsg)=>{alert(erroMsg)}  
  146. );  
  147. 原生介面的程式碼也要記得寫,不過也沒啥好說的了,按原生安卓一樣就可以了。  

相關推薦

React-NativeAndroid:原生介面React介面相互呼叫

這裡原生介面是指用佈局檔案實現或Java程式碼實現view的Activity,React介面是指用ReactJS實現的介面的Activity。 從某種角度看,React只是充當了Android裡的view層,因此原生介面與React介面的相互呼叫及資料傳遞同原生介面之間的互

React NativeAndroid原生通過DeviceEventEmitter傳送訊息給js

1 問題 Android原生向js發訊息,並且可以攜帶資料 2 實現原理 Android原生可以使用RCTEventEmitter來註冊事件,然後這裡需要指定事件的名字,然後在js那端進行監聽同樣事件的名字監聽,就可以收到訊息得到資料 Android註冊關

React-Native開發九 react-navigationAndroid的打包釋出

1前言 RN的開發中正式釋出前需要打包與簽名,然後才能上架各家應用市場。打包需要將js與圖片資原始檔打包進apk檔案中,生成index.android.bundle與index.android.bundle.meta檔案。下面介紹RN開發中打包APK的主要步驟,IOS沒研究過,不再本

react native 編寫android原生模組

1、android studio 開啟RN專案   2、建立類檔案,繼承ReactContextBaseJavaModule,編寫js要呼叫的方法         3、建立包管理類,實現ReactPackage介面 &

帶你徹底看懂React NativeAndroid原生控制元件之間的對映關係

此文基於react natve的 September 2018 - revision 5 版本 本人學校畢業後就當了安卓爬坑專業戶,3年來總算爬習慣了,不料今年掉進了RN這個天坑,從此開始了我的悲慘人生。。。Anyway,RN的思想還是值得學習的,今天就從Android的角度開始分析一下react nati

react-native-android-unity(一)react-native加入android原生

 本人是做後端php的,對各類語言和方向都有興趣,多而不精。最近公司專案有一個移動端app,決定採用react-native開發,專案中有這麼個要求,要求react-native中嵌入原生頁面,然後原生頁面嵌入unity,並實現原生和unity之前相互通訊,網路查詢資料後實現

react-native android 配置gif圖片的使用----------小白的天堂

React-native顯示動態圖片(gif)的配置 突然心血來潮,想把專案中的loading效果換成動態圖片的樣式,這樣會好看一些不會那麼單調。然後開始了我的踩坑之路。。。。 首先,檢視官方網站(react-native中文網),然後選擇對應自己的版本號的文件 我的是0.50

關於React-nativeAndroid原生模組和元件的寫法

原生模組就是把Android裡的API匯出來給JS呼叫,說簡單一點,就是讓自己寫的Java函式能夠在React Native的js程式碼裡呼叫。比如一些實現高效能的、多執行緒的程式碼,還有譬如圖片處理、資料庫、或者各種高階擴充套件等等。 舉個栗子: Toas

React Native Android混合開發,及遇到的各種坑

最近自己也是剛在學習React Native的知識,在學習到React Native 嵌入到原生應用的時候,感覺遇到了各種坑,這裡做一下記錄。若有說得不對的地方,謝謝大家糾正。 React Native嵌入到原生應用的教程在其官方指導文件裡也有,但是感覺很多注意點沒講到,現

React NativeAndroid 和 iOS在點選觸發事件時的相容性處理

最近,我在專案中遇到了一個bug,bug的情況描述大致如下: 當點選按鈕A時,彈出彈層,彈層有一個按鈕B,邏輯是:當點選按鈕B時,首先彈層消失,緊接著開始調取C介面流程。在Android上正確顯示,但是iOS中只是彈層消失,並沒有調取C介面事件。 對於這種情況,我之前開發過

React NativeAndroid 5.0以下系統WebView訪問https頁面變成空白頁

在我們的React Native專案中,需要開發一個tab頁面專門配置三方h5連結,供使用者瀏覽。自動化測試:Android 5.0以下系統此tab頁面為空白頁面。看效果: 而我們去檢視這個三方的

React-Native Android應用開發踩坑紀 (一)————windows環境下配置

歡迎轉載,轉載註明出處: 我不只是看客 自從在公司中被老大安利了移動開發的未來 React-Native之後開始關注相關,想嘗試相關app開發。正好畢業準備畢設,腦子一熱就選擇了RN來開發一款app……題目上交就不能改了,現在好後悔。。。但硬著頭皮上吧 ,廢

React native android的圖示和啟動圖片

哎哎呀呀,上篇說到了react native的IOS的圖示和啟動圖片的設定,其實最主要的是尺寸!相應的尺寸設定好了以後就不會報錯了!ok~這篇說的是React native的android的圖示和啟動頁面!!!!!1.圖示:其實android的圖示設定很簡單,一般情況下只需要替換就可以了(當然你也可以不去替換

React Native封裝Android原生控制元件

第一步: 我們首先要建立一個RN專案: react-native init 你的專案名 第二步: 是用Android studio開啟RN專案中的Android專案。 在新建一個資料夾用於存放我們封裝的控制元件,結構如下: 第三步: 建立V

React NativeListView的講解應用

          在安卓原生開發中,ListView是很常用的一個列表控制元件,那麼React Native(RN)如何實現該功能呢,這裡簡單的講解下。        ListView.js原始碼截圖:               從原始碼中可知RN中的ListView是

React Native內部方法常用幾種寫法和呼叫規則

1 簡單部分程式碼 export default class App extends Component<Props> { render() { return (

React Nativejs呼叫Android原生使用Callback傳遞結果給js

1 問題 上面的文章只是呼叫安卓原生顯示Toast,但是我們一般會需要呼叫安卓的程式碼然後去拿回結果給js,但是我們知道在android層js呼叫的這個函式返回值必須的void,所以我們需要用到Callback,Callback一般用於同步,也就是說直接呼叫

React-Native系列Android——NativeJavascript通信原理(一)

from 直接 最新 一點 明顯 rem 負責 receive esp React-Native最核心的是Native與Javascript之間的通信,並且是雙向通信

React Native通知欄訊息提示(android)

React Native之通知欄訊息提示(android)   一,需求分析與概述 1.1,推送作為手機應用的基本功能,是手機應用的重要部分,如果自己實現一套推送系統費時費力,所以大部分的應用都會選擇使用第三方的推送服務,如極光推送。 1.2,jpush-react-native 

React Native 橋接原生 iOS 以及 Android 獲取 APP 版本號

在使用React Native進行跨平臺開發過程中,或多或少需要涉及到原生開發,這裡主要說一下如何橋接原生 iOS 以及 Android,在此以獲取 APP 版本號為例。 iOS 橋接 iOS 橋接比較簡單,只需要建立一個 Module 類,實現 RCTBridgeModule 協議就好。 首先我們需要建