利用 Native.js 實現 Android 與 HTML 資料的互動

hogen發表於2018-01-02

Native.js技術,簡稱NJS,是一種將手機作業系統的原生物件轉義,對映為JS物件,在JS裡編寫原生程式碼的技術,由DCloud(數字天堂)公司開發。說人話就是:通過 native.js, 你可以在 html 程式碼的<script></script>標籤中用 native.js語法直接呼叫 Android 原生 API。

本次文章主要目的是學習如何利用 Native.js 實現在 HTML 中獲取 Android 原生程式碼的資料,很多人一看到”html與Android資料互動”可能都會想到WebView,在 webview 中使用 jsBridge,是的,我一開始也是這個念頭,遺憾的是我當時的專案使用的是 DCloud 的 MUI 框架,所有頁面都是由 html+js 組成,幾乎沒怎麼用到 Android 原生控制元件,所以這個方法行不通,當然現在的hybrid 模式的框架,原理都是封裝一層 JSBridge ,通過 JSBridge 去訪問原生的硬體功能。

本次專案是從AndroidStudio 建立 Hybrid App工程專案基礎修改而來,把AndroidStudio 建立 Hybrid App工程沒有用到的 MainActivity 加上(如果被刪掉了就再建立一個),大體思路就是在 MainActivity 資料持久化,然後在 html 頁面通過 native.js 獲取,MainActivity修改程式碼如下:

public class MainActivity extends ListActivity {
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //存放一些資料到SharePreferences
        initData();
        setListAdapter(new MyListAdapter());
        getListView().setTextFilterEnabled(true);
    }

    private void initData() {
        //Log.d(TAG, "initData: hello");
        SharedPreferences sharedPreferences = getSharedPreferences("data", Context.MODE_PRIVATE);
        SharedPreferences.Editor edit = sharedPreferences.edit();
        edit.putString("data1","aaaa").putString("data2","bbbb").apply();
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        super.onListItemClick(l, v, position, id);
        Intent intent = new Intent(this,activityInfos[position].clazz);
        startActivity(intent);
    }

    ActiviyInfo[] activityInfos = new ActiviyInfo[]{
            new ActiviyInfo("SDK_APP",SDK_Runtime.class),
            new ActiviyInfo("SDK_WEBAPP",SDK_WebApp.class)
    };
    class ActiviyInfo{
        String title;
        Class<? extends Activity> clazz;

        public ActiviyInfo(String title, Class<? extends Activity> clazz) {
            this.title = title;
            this.clazz = clazz;
        }
    }
    class MyListAdapter extends BaseAdapter {

        @Override
        public int getCount() {
            return activityInfos.length;
        }

        @Override
        public Object getItem(int position) {
            return activityInfos[position];
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            TextView tv = new TextView(parent.getContext());
            tv.setHeight(100);
            tv.setGravity(Gravity.CENTER);
            tv.setText(activityInfos[position].title);
            convertView = tv;
            return convertView;
        }
    }
}
複製程式碼

上面程式碼我直接用了 Android-SDK 中 HBuilder-Integrate 中的程式碼,MainActivity 中的SDK_Runtime 和 SDK_Webapp 類 直接從 HBuilder-Integrate/src下拷貝過來的

SDK_Runtime 和 SDK_Webapp 類

當然,在AndroidManifest.xml中要配置 activity(這裡貼出主要程式碼)

<application
    android:name="io.dcloud.application.DCloudApplication"
    android:allowClearUserData="true"
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    android:largeHeap="true">
    <activity
        android:name="io.dcloud.PandoraEntry"
        android:configChanges="orientation|keyboardHidden|keyboard|navigation"
        android:hardwareAccelerated="true"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:screenOrientation="user"
        android:theme="@style/TranslucentTheme"
        android:windowSoftInputMode="adjustResize">
    </activity>
    <activity android:name=".MainActivity"
        android:theme="@style/AppTheme">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <activity
        android:name="io.dcloud.PandoraEntryActivity"
        android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation|mcc|mnc|fontScale"
        android:hardwareAccelerated="true"
        android:label="5+Debug"
        android:launchMode="singleTask"
        android:screenOrientation="user"
        android:theme="@style/DCloudTheme"
        android:windowSoftInputMode="adjustResize">
    </activity>
    <activity
        android:name=".SDK_Runtime"
        android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation|mcc|mnc|fontScale"
        android:screenOrientation="sensor">
    </activity>
    <activity
        android:name=".SDK_WebApp"
        android:configChanges="orientation|keyboardHidden|screenSize|keyboard|navigation|mcc|mnc|fontScale"
        android:screenOrientation="user"
        android:theme="@android:style/Theme.Translucent">
    </activity>
    <service
        android:name="io.dcloud.common.adapter.io.MiniServerService"
        android:exported="true" />
</application>
複製程式碼

執行程式後介面是這樣子

執行

接下來就是在html中取值了

  • 首先找到呼叫native.js的那部分html頁面

njs.html

  • 根據 DCloud 提供的如何使用 native.js 語法來寫

      <!DOCTYPE HTML>
      <html>
      <head>
      	<meta charset="utf-8"/>
      	<meta name="viewport" content="initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
      	<title>Hello H5+</title>
      	<link rel="stylesheet" href="../css/common.css">
      	<script type="text/javascript" src="../js/common.js"></script>
      	<script type="text/javascript">
      		function njsAlertForAndroid(){
      			<!--全域性環境-->
      			var mainActivity = plus.android.runtimeMainActivity();
      			<!--導包-->
      			var Toast = plus.android.importClass("android.widget.Toast");
      			var Context = plus.android.importClass("android.content.Context");
      			var SharedPreferences = plus.android.importClass("android.content.SharedPreferences");
      			var sp = mainActivity.getSharedPreferences("data",Context.MODE_PRIVATE);
      			<!--var a = sp.getString("a","");-->//這種寫法不行
      			<!--var b = sp.getString("b","");-->
      			var value1 = plus.android.invoke(sp,"getString","data1","");
      			var value2 = plus.android.invoke(sp,"getString","data2","");
      			var toast = Toast.makeText(mainActivity,"data1:"+value1+"\n"+"data2:"+value2,Toast.LENGTH_SHORT);
      			toast.show();
      		}
          </script>
      </head>
      <body>
      <header id="header">
      	<div class="nvbt iback" onclick="back(true);"></div>
      	<div class="nvtt">Native.JS</div>
      	<div class="nvbt idoc" onclick="openDoc('Native.JS Document','/doc/native.js.html')"></div>
      </header>
      <div id="dcontent" class="dcontent">
      	<br/>
      	<ul class="dlist">
      		<li class="ditem" onclick="njsAlertForAndroid()">native.js呼叫Android原生程式碼資料</li>
      		<li class="ditem" onclick="clicked('njs_efficient.html')">native.js高階API</li>
      	</ul>
      	<br/>
      	<div class="button button-waring"
      		 onclick="plus.runtime.openURL('http://ask.dcloud.net.cn/article/114');">更多示例...
      	</div>
      </div>
      <div id="output">
      	Native.JS一種把作業系統的原生物件轉義,對映為JS物件,在JS裡編寫原生程式碼的技術。可通過plus.android.*和plus.ios.*提供的API分別呼叫Android和iOS平臺的Native
      	API。
      </div>
      </body>
      <script type="text/javascript" src="../js/immersed.js"></script>
      </html>
    複製程式碼

注意,限於篇幅,我把njs.html的一些無關程式碼程式碼簡化了

  • 執行程式,可以看到,值已經成功取出來了

最後的效果

更多關於使用 native.js的例子可以檢視這裡: Native.js示例彙總

hogenlaw.com ,歡迎來踩!

相關文章