范例解析:学习PhonegapPlugin主板模式

  

1. 简介Phonegap的主板模式

     HTML5/PhoneGap是由第三方公司所开发的框架,其内部采用主板模式来整合(组合)了HTML5、WebView和众多的Java插件(Plugin)。此主板模式嵌入于Android的UI框架哩,跟WebView搭配得非常的紧密,来共同支持HTML5。也就是支持Web App的开发及执行。由于Phonegap也是开源开放的软件,其主板模式的设计和应用,可成为我们的学习范例。

   首先,其主板模式提供了IPlugin通用性接口,Java代码如下: 

 

// PhoneGap的IPlugin通用性接口定义 

//------------------------------------------------------ 

package com.phonegap.api; 

import org.json.JSONArray; 

import android.content.Intent; 

import android.webkit.WebView; 

 

   PluginResult execute(String action, JSONArray args, String callbackId);

   void setContext(PhonegapActivity ctx); 

   public boolean isSynch(String action); 

   void setView(WebView webView); 

   void onPause(boolean multitasking);

   void onResume(boolean multitasking);

   void onNewIntent(Intent intent);

   void onDestroy();

   void onActivityResult(int requestCode, int resultCode, Intent intent);

   boolean onOverrideUrlLoading(String url);

 } 

// End  

 

这个接口定义了许多个函数,其中最主要的就是execute()通用性函数了。如下图:

         

     Phonegap定义一个Plugin父类来实现<通用性>的IPlugin接口。如下图: 

         

 然后,以Java来撰写这个实现类,其Java代码如下: 

 

// Phonegap的源代码

// Plugin.java

// -------------------------------------------------------------

package com.phonegap.api;

import org.json.JSONArray;
import org.json.JSONObject;
import android.content.Intent;
import android.webkit.WebView;

public abstract class Plugin implements IPlugin {

       public String id;
       public WebView webView; // WebView object
       public PhonegapActivity ctx; // PhonegapActivity object

       public abstract PluginResult execute(String action, JSONArray args, String callbackId);
       public boolean isSynch(String action) {   return false;   }
       public void setContext(PhonegapActivity ctx) {     this.ctx = ctx;    }
       public void setView(WebView webView) {
                  this.webView = webView;
           }
       public void onPause(boolean multitasking) {}
       public void onResume(boolean multitasking) {}
       public void onNewIntent(Intent intent) {}
       public void onDestroy() {}
       public void onActivityResult(int requestCode, int resultCode, Intent intent) {}
       public boolean onOverrideUrlLoading(String url) {   return false;  }
       public void sendJavascript(String statement) {
                 this.ctx.sendJavascript(statement);
           }
       public void success(PluginResult pluginResult, String callbackId) {
              this.ctx.sendJavascript(pluginResult.toSuccessCallbackString(callbackId));
           }
       public void success(JSONObject message, String callbackId) {
              this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK,

                                                message).toSuccessCallbackString(callbackId));
           }
       public void success(String message, String callbackId) {

                    this.ctx.sendJavascript(new PluginResult(PluginResult.Status.OK,

                    message).toSuccessCallbackString(callbackId));
           }
       public void error(PluginResult pluginResult, String callbackId) {

              this.ctx.sendJavascript(pluginResult.toErrorCallbackString(callbackId));
           }
       public void error(JSONObject message, String callbackId) {

              this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR,

              message).toErrorCallbackString(callbackId));
           }

       public void error(String message, String callbackId) {

              this.ctx.sendJavascript(new PluginResult(PluginResult.Status.ERROR,

              message).toErrorCallbackString(callbackId));
}}
// End

  

      于是,这个抽象父类担任两项任务:

  • 实现了IPlugin接口,这是提供给众多Client来使用的外部接口。我们以”CI”(Interface for Client)来表示之。
  • 定义了抽象函数,如上图里的execute()函数,成为提供给众多子类别来实现的内部接口。我们以<I>来表示之。

 如下图:     

 

      这是简化型(或称退化型)的主板模式。此图里的Plugin抽象父类和两个接口,整合起来成为一个典型的软件主板。如下图: 

       

   这个Plugin软件主板是用来整合(组合)了HTML5、WebView和众多的Java插件(Plugin),所以我们称之为:Phonegap的Plugin软件主板。如下图:

       

 

2.简介Phonegap的主板模式

  基于这个主板,我们就能开始进行组合了。此时,可设计一个子类,并且装配到主板的<I>接口上。如下图:

        

      由子类来实现内部接口<I>。基于PhoneGap的框架,就可以写HTML5/JS模块来调用Java插件(即上图里的myPlugin子类)。在App执行时,用户会使用WebView画面而触发UI事件,JS就负责处理这些事件。必要时,JS会透过WebView(包含幕后的WebKit引擎)调用到IPlugin通用性接口的函数,转而调用Java插件里的execute()函数。如下图: 

       

      由于IPlugin接口只提供单一函数:execute();使得PhoneGap也只能提供单一函数:exec()。

 

3.通用性接口与Proxy-Stub设计模式

    然而,在HTML5_JS里可能有多个函数,例如play()和stop()等。于是,在HTML5_JS里,必须从play()函数转而调用PhoneGap.exec()函数这个PhoneGap.exec()再透过WebView而呼叫到IPlugin.execute()。如果我们在上述架构里面,加上一个myProxy类别,它包装了PhoneGap.exec()函数,扮演Java Plugin的Proxy(代理者)角色,如下图所示: 

      

   此时,HTML5_JS里面就看不到PhoneGap.exec()函数了,其好处是:

• 一方面让HTML5_JS程序代码比较单纯;

• 另一方面,让HTML5_JS与PhoneGap.exec()两者相依性(Dependency)降低,让HTML5_JS不受制于PhoneGap的框架界面。也因而提升了PhoneGap框架接口的变动自由度。

  通常,在框架设计里,myProxy和myStub会是成对的,这称为Proxy-Stub模式。如下图所示:

       

  于此,你已经观摩了如何使用proxy-stub模式来封装PhoneGap.exec()界面。

~ End ~