如果感覺略有用處,點贊支持下作者。上一篇將關于 WebView 的設置仔細的捋了一遍,我們通過 WebViewController 這個類完成了所有 WebView 的設置,并且在布局的時候,只需在布局文件中引入這個類的完整包名,前提是這個類要繼承于 WebView,就可以完成所有 WebView 的設置,具體可參考上一篇 當下主流 APP,Hybrid app 中需要熟練掌握的交互知識(一) 其實有人就說到了,現在有現成的框架可,那我的出發點是從自己動手開始,再去接觸框架,這個系列我們一步步來!
那么本篇將就以下幾點展開:
頁面布局相同情況下Activity 的 共用問題。
在原生與網頁混合的開發狀態下,如何確定頁面跳轉以及參數傳遞。
根據服務端發送的 Js 接口名去做具體實現
Activity 共用
這是當下很多 WebApp 都在使用的一個套路,除了避免了創建多個 Activity 后影響性能之外,還可以保持項目「友好」的結構!這樣的處理大多適應于這樣的場景:
頁面布局上方只有一個 ToolBar 或者 ActionBar 等等的標題欄
下方則是一個 WebView 用于呈現網頁內容
如此則可以將共同的屬性提取出來,WebView 則不用管,都是一致的東西。ToolBar 上無論是標題還是按鈕的設置,當點擊了某處后我們會進入我們在本地實現的網頁接口,具體的原理請看下面的詳細解釋!
一 、建立共用的 Activity:
我們將之命名為 NewWebViewActivity
//獲取到消息處理類傳過來的 url 網址
String url = getIntent().getStringExtra("url");
//獲取到消息處理類傳過來的動畫操作
int anim = getIntent().getIntExtra("animation", 0);
if (url == null) {
finish();
}else if (url.equals(Constants.urlHostBase + Constants.urlLogIn)){
baseWebView.loadUrl(url);
topToolbar.setVisibility(View.GONE);
} else {
baseWebView.loadUrl(url);
//用動畫文件判斷新開頁面
if (anim == R.anim.slide_right_out) { //當所有的新開頁面 是從右往左打開時(表示新開頁面)
//添加返回按鈕
backImageView.setImageResource(R.drawable.returns);
//變為顯示狀態
backImageView.setVisibility(View.VISIBLE);
//返回鍵點擊事件
backImageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish(); //關閉頁面
//設置頁面退出動畫為從左往右退出
overridePendingTransition(R.anim.none, R.anim.slide_right_out);
}
});
}
}
可以看到,并沒有多少邏輯。我們這樣就可以所有新開的頁面添加一個返回鍵了,前提是有一個消息處理的類來完成打開頁面的 url 參數設置,以及動畫參數設置,其實實現起來也是很簡單!往下看
二 、建立共用的 Activity 的布局:
我們緊接著需要將我們這個 Activity 布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_new_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:theme="@android:style/Animation.Toast"
android:background="@android:color/white"
tools:context="com.lansum.eip.activity.NewWebViewActivity">
<!-- 標題欄 -->
<android.support.v7.widget.Toolbar
android:id="@+id/web_top_toolbar"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_alignParentTop="true"
android:background="#00a6ff"/>
<!-- WebView -->
<com.lansum.eip.webview.WebViewController
android:id="@+id/base_web_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/web_top_toolbar" />
<!-- 標題欄右上角圖片點擊按鈕 默認隱藏狀態 下同 -->
<ImageView
android:id="@+id/right_Button"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignRight="@id/web_top_toolbar"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_marginRight="16dp"
android:layout_marginTop="30dp"
android:visibility="gone" />
<!-- 標題欄正中顯示的標題 根據點擊區域切換標題內容 -->
<TextView
android:id="@+id/toolbar_text_top"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_centerHorizontal="true"
android:layout_marginTop="32dp"
android:textColor="@android:color/white"
android:textSize="18sp" />
<!-- 標題欄左上角用于關閉打來頁面的圖片按鈕 -->
<ImageView
android:id="@+id/back_web"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignLeft="@id/web_top_toolbar"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_marginLeft="16dp"
android:layout_marginTop="30dp"
android:visibility="gone" />
<!-- 右上角文字點擊按鈕 -->
<TextView
android:id="@+id/right_Button_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@id/web_top_toolbar"
android:layout_alignTop="@id/web_top_toolbar"
android:layout_marginRight="16dp"
android:layout_marginTop="32dp"
android:textColor="@android:color/white"
android:textSize="18sp"
android:visibility="gone" />
</RelativeLayout>
布局文件很簡單,我們將標題欄上正中標題,左上角關閉頁面的圖片點擊按鈕,右上角的文字提交按鈕以及圖片點擊按鈕都放在了布局中,那接下來就是如何去控制他們的顯示時機,以及按下后的反饋了!
建立好了這個用于展示我們所有網頁的共用 Activity 后,就是我們本篇的核心類了,敲黑板!!
核心類 HtmlMessageForLocal
在開始之前我們先將思路捋清楚
處理所有網頁的接口實現,以及跳轉操作和添加標題欄上的按鈕添加。
此類用于接收我們點擊或打開 WebView 服務端暴漏給我們的接口,我們負責具體實現!
將我們實現的方法上加上 @JavascriptInterface 注解
此注解表明所有服務端 Js 接口,都會進入我們自定義的這個方法里找同名方法,直接執行里面的邏輯!
好了,通過以上說明相信明眼的你可以發現,這是一個網頁與我們本地的交互的核心類,所有的交互邏輯實現都需要在這里進行!
接下來我們分層進行,一層層,一個個方法的具體實現步驟,來剖析整個過程。
一 、判斷接口名執行具體的方法:
@JavascriptInterface
public void callHandler(final String methodName, final String data, final String callbackName) {
Log.e(TAG, "Method:" + methodName);
if (methodName.equals("openAttendanceFromJS")) {
openAttendanceFromJS(data); // 打開新窗口
}
}
這里只是起到了判斷作用,特定的方法執行特定的操作,就比如上面這個方法,只負責用戶點擊了 WebView 去打開新的 WebView 的所有操作。
如何判斷
/**
* Js 與 Native(android 原生交互)
* Native 調用 JS 方法
* @param methodName Js 方法名
* @param data 需要用到的數據 比如圖片資源需要傳遞的數據 以下代碼的實體類為 RightInfo
我們需要聲明一個實體類 用到什么數據資源就傳給這個參數
* @param callbackName 回調的方法名 這里具體用不到
*/
@JavascriptInterface
public void callHandler(final String methodName, final String data, final String callbackName) {
Log.e(TAG, "Method:" + methodName);
if (methodName.equals("openAttendanceFromJS")) {
openAttendanceFromJS(data); // 打開新窗口
} else if (methodName.equals("addRightBarButtonItemFromJS")) {
addRightBarButtonItemFromJS(data);// 添加右上角按鈕
}
/**
* 打開新窗口
* @param url
*/
protected void openAttendanceFromJS(String url) {
Log.i("js", url);
// TODO Auto-generated method stub
Intent intent = new Intent(ActivityCollector.getTopActivity(), NewWebViewActivity.class);
intent.putExtra("url", url);
intent.putExtra("animation", R.anim.slide_right_out);
intent.putExtra("animation", R.anim.slide_right_in);
ActivityCollector.getTopActivity().startActivity(intent);
}
/**
* 設置右上角圖片按鈕
* @param data
*/
protected void addRightBarButtonItemFromJS(String data) {
topRightImage.setBackgroundResource(imageId); //找到圖片按鈕資源
topRightImage.setVisibility(View.VISIBLE); //設置為可見狀態
topRightImage.setOnClickListener(new View.OnClickListener() { //此按鈕點擊事件
@Override
public void onClick(View v) {
Activity activity = ActivityCollector.getTopActivity();//獲取到棧頂 Activity
activity.runOnUiThread(new Runnable() { //強制運行到主線程
@Override
public void run() {
//找到共用打的 WebView
ActivityCollector.getTopActivity().findViewById(R.id.base_web_view);
activity.overridePendingTransition(R.anim.push_bottom_out, R.anim.push_bottom_in);
//找到對應 web url網址
baseWebView.loadUrl("javascript:" + rightInfo.funcName);
}
});
}
});
}
在這里用兩個方法舉例,重要的步驟在這里都呈現了出來,根據我們服務端和 Android 端的需求做相應邏輯和方法的疊加就可以了!
總結
此次在這里將 Js 與 Native 的交互做了一個簡單總結記錄,整理了通用流程和思想,下個系列將使用當下比較流行的 Hybrid APP 框架來實現一個總體的處理流程。