標籤:getname exec public ide html5 代碼 nal eve 作用
上一篇文章說到,當利用WebViewClient或者WebChromeClient來處理由html頁面傳過來的請求的時候,都會將相應的服務名稱,操作方法和相應的參數資料傳給一個叫PluginManager的類。
PluginManager類的作用是什嗎?
大家知道,當利用Android原生環境的功能。比方照像機。比方相冊等,這些功能都是非常分散的,說不清楚什麼時候是須要這些功能,什麼時候是不須要這些功能的,所以我們希望可以像外掛程式一樣。須要的時候就載入進來,不須要的時候不去理他,而PluginManager類就是一個這種管理類。
它主要負責幾件事情:
1)進入HTML頁面的時候,去載入我們定義好的控制項。
mPluginManager = new PluginManager(this);mPluginManager.loadPlugin();
那麼PluginManager怎麼知道本個應用要載入多少plugin來去響應由Html頁面來的請求呢?
我們是通過一個叫plugin.xml設定檔來定義的。
<plugins> <plugin name="App" class="com.lms.xxx.bridge.plugin.App" /> <plugin name="Toast" class="com.lms.xxx.plugin.Toast" /> <plugin name="Dialog" class="com.lms.xxx.bridge.plugin.Dialog" /> <plugin name="User" class="com.lms.xxx.bridge.plugin.User" /></plugins>
比方在上面的設定檔裡,我們會載入App, Toast, Dialog 和 User 這幾個plugin。
能夠聯想到,Toast和Dialog都是Android原生環境下的顯示表單,我們儘管用html頁面來實現介面,可是為了保持整個應用的一致性,我們就會用到原生環境中的Toast或者我們自己定義的對話方塊等控制項。
須要用到什麼,就在這裡定義什麼。
我們再來看一下loadPlugin方法:
public void loadPlugin() {int identifier = context.getResources().getIdentifier("plugins", "xml",context.getPackageName());if (identifier == 0) {pluginConfigurationMissing();}XmlResourceParser xml = context.getResources().getXml(identifier);try {int eventType = -1;while ((eventType = xml.next()) != XmlResourceParser.END_DOCUMENT) {if (eventType == XmlResourceParser.START_TAG) {String name = xml.getName();if ("plugin".equals(name)) {String pluginName = xml.getAttributeValue(null, "name");String className = xml.getAttributeValue(null, "class");configs.put(pluginName, className);}}}} catch (XmlPullParserException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
能夠看到,這就是解析plugins.xml檔案。然後將相應的外掛程式類名給放到configs中,configs定義例如以下:
private HashMap<String, String> configs = new HashMap<String, String>();private HashMap<String, IPlugin> plugins = new HashMap<String, IPlugin>();
通過loadPlugin方法,我們就將在plugins.xml中定義好的外掛程式,給載入到configs中去了。configs裡存放的僅僅是類名。而plugins存放的才是實現,只是我們這裡不須要關心這個。
在這裡。在plugins.xml檔案裡定義的name屬性就是這個服務名稱。
2)依據請求的服務名稱和操作方法等,為這個請求找到相應的Plugin去處理。
String execResult = mPluginManager.exec("service", "action", args);
看一下exec方法,
public String exec(String service, String action, JSONObject args) throws PluginNotFoundException { IPlugin plugin = getPlugin(service);...PluginResult result = plugin.exec(action, args);...}
在上面的邏輯能夠看到。PluginManager會利用getPlugin方法拿出相應的服務,例如以下:
public IPlugin getPlugin(String pluginName) throws PluginNotFoundException {String className = configs.get(pluginName);if(className==null){throw new PluginNotFoundException(pluginName);}if (plugins.containsKey(className)) {return plugins.get(className);} else {return addPlugin(className);}}
這樣,我們就拿到了一個實現了IPlugin介面中的Plugin實作類別。
IPlugin是一個介面,其定義例如以下:
public interface IPlugin {public static final String SERVICE = "service";public static final String ACTION = "action";public static final String ARGS = "args";/** * 運行請求 * * @param action * 功能 * @param args * 參數 * @return pluginResult 結果 */public PluginResult exec(String action, JSONObject args)throws ActionNotFoundException;
裡面定義的最重要的方法就是exec方法。每個我們自己定義的外掛程式都要實現這個介面,只是在這裡。我們先實現了一個抽象基類Plugin。在裡面實現一些公用的邏輯,而對於詳細的實現,再由Plugin的子類去繼承。
public abstract class Plugin implements IPlugin {protected DroidHtml5 context;
比方,我們拿上面的Toast類。其就會繼承Plugin。然後依據相應的服務去實現相應的邏輯,調用原生環境的Toast。
public class Toast extends Plugin {@Overridepublic PluginResult exec(String action, JSONObject args)throws ActionNotFoundException {if ("makeTextShort".equals(action)) {return makeTextShort(args);}else if ("makeTextLong".equals(action)) {return makeTextLong(args);} else {throw new ActionNotFoundException("Toast", action);}}private PluginResult makeTextShort(JSONObject args) {try {String text = args.getString("text");android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show();} catch (JSONException e) {e.printStackTrace();return PluginResult.newErrorPluginResult(e.getMessage());}return PluginResult.newEmptyPluginResult();}private PluginResult makeTextLong(JSONObject args) {try {String text = args.getString("text");android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_LONG).show();} catch (JSONException e) {e.printStackTrace();return PluginResult.newErrorPluginResult(e.getMessage());}return PluginResult.newEmptyPluginResult();}}
從上面的代碼。相信大家非常easy就行理解了Plugin機制了。
3)從Html頁面來調用。
我們在Android原生環境定義了這麼一套Plugin機制。那麼在Html裡面,也能夠有這種一套介面方法,來相應不同的Plugin,所以我們在javascript中也會定義各種各樣的對象。
比方上面描寫敘述的Toast外掛程式,我們能夠在javascript中定義一個相應的對象。例如以下:
var Toast = {makeTextShort : function(text) {return exec("Toast", "makeTextShort", JSON.stringify(text));},makeTextLong : function(text) {return exec("Toast", "makeTextLong", JSON.stringify(text));}}
這裡,我們能夠看到Toast的makeTextShort方法,會調用上一篇文章中講到的exec方法,由於彈窗顯示這樣的東西肯定是同步的,不會說做了一會流程,突然間就跑出一個框來。告訴我,你剛才做錯了。對吧。
而在這裡,我們就會將服務名(Toast)。操作方法(makeTextShort)。還有顯示的內容(JSON.stringfy(text))等通過exec方法,然後利用WebChromeClient的onJsPrompt方法。將命令傳遞給PluginManager,由PluginManager來處理。
public boolean onJsPrompt(WebView view, String url, String message,String defaultValue, JsPromptResult result) {System.out.println("onJsPrompt:defaultValue:" + defaultValue + "|" + url + "," + message);JSONObject args = null;JSONObject head = null;try {// message:{"service" : "XX", "action" : "xx"}head = new JSONObject(message);if (defaultValue != null && !defaultValue.equals("")) {try {args = new JSONObject(defaultValue);} catch (Exception e) {e.printStackTrace();}}String execResult = mPluginManager.exec(head.getString(IPlugin.SERVICE),head.getString(IPlugin.ACTION), args);result.confirm(execResult);return true;
4)我們會把這些定義的外掛程式對象,還有同步(exec),非同步運行(exec_sync)的方法都寫到一個javascript檔案裡,方便統一管理,所以一般這個檔案內容就會像以下這樣:
var Toast = {makeTextShort : function(text) {return exec("Toast", "makeTextShort", JSON.stringify(text));},makeTextLong : function(text) {return exec("Toast", "makeTextLong", JSON.stringify(text));}}var Dialog = { ...}var AndroidHtml5 = {..../* * exec_asyn調用的方法 @params {JSONObject} cmd 服務名和動作命令 @params {String} args 參數 */callNative : function(cmd, args, success, fail) {....},<span style="white-space:pre"></span>...callBackJs : function(result,key) {...}};/* * Html5與Android同步互動介面 */var exec = function(service, action, args) {var json = {"service" : service,"action" : action};var result_str = prompt(JSON.stringify(json), args);var result;try {result = JSON.parse(result_str);} catch (e) {console.error(e.message);}...}/* * Html5與Android非同步互動介面 */var exec_asyn = function(service, action, args, success, fail) {var json = {"service" : service,"action" : action};var result = AndroidHtml5.callNative(json, args, success, fail);}
結束。
Android與WebView的外掛程式管理機制