2013-04-06 57 views
3

我有和使用PhoneGap構建的應用程序,並且我試圖從本機代碼與Javascript進行通信。使用PhoneGap從Android進行Javascript調用

DroidGap擴展類

@Override 
public void onCreate(Bundle savedInstanceState) { 
    Logger.log("oncreate"); 
    super.onCreate(savedInstanceState); 
    super.init(); 
    super.appView.getSettings().setJavaScriptEnabled(true); 
    super.appView.getSettings().setSupportZoom(true); 
    super.appView.getSettings().setBuiltInZoomControls(true); 
    super.appView.getSettings().setDisplayZoomControls(false); 
    jsinterface = new CommunicationInterface(this, appView); 
    super.appView.addJavascriptInterface(jsinterface, "communicationinterface"); 
} 

的javascriptinterface:

public class CommunicationInterface { 
    private WebView mAppView; 
    private DroidGap mGap; 

    public CommunicationInterface(DroidGap gap, WebView view) { 
     mAppView = view; 
     mGap = gap; 
    } 

    public String getTestString() { 
     return "teststring"; 
    } 

    public void parse(Object o) { 
     Logger.log(o); 
    } 
} 

Javacript位於外部文件(我創造出具有在header這一行的HTML文件:<script type="text/javascript" src="scripts.js"></script>

Scripts.js

function sendToInterface() { 
    alert("alert"); 
    var map = new Object(); 
    (...) 
    window.communicationinterface.parse(map); //communication js -> android seems to work. 
} 

我在其他文章中看到它可以在PhoneGap和Android之間進行通信,但是因此我沒有取得任何成功。我確實設法創建了一個提醒,但那是loadUrl("javascript:alert('Alert');"),但我也讀過,你不應該這樣做,因爲這就是sendJavascript()的原因(它會導致泄漏,重新加載頁面等)。我試圖通過sendJavascript()的方法來拍了幾個字符串,但無濟於事:

  • sendJavascript("javascript:alert('Alert');")
  • sendJavascript("javascript:sendToInterface();")
  • sendJavascript("sendToInterface();")
  • sendJavascript("window.sendToInterface();")

如何從本地通信 - > PhoneGap(或者我已經有什麼問題)?因此,其他職位和問題沒有幫助我解決這個問題。

閱讀:

編輯

我寫了一個工作項目:

的Java部分

import org.apache.cordova.DroidGap; 
import org.json.JSONException; 
import org.json.JSONObject; 

import android.os.Bundle; 
import android.util.Log; 

public class App extends DroidGap { 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    super.loadUrl("file:///sdcard/ds/index.html"); 
    System.out.println("loading from sdcard"); 
    Thread t = new Thread() { 
     public void run() { 
     try { 
      for (int i = 0; i < 3; i++) { 
      sleep(2000); 
      sendValue("value " + i, "another vlaue " + i); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     }; 
    }; 
    t.start(); 
    } 

    public void sendValue(String value1, String value2) { 

    System.out.println("sendvalue in app"); 
    JSONObject data = new JSONObject(); 
    try { 
     data.put("value1", value1); 
     data.put("value2", value2); 
    } catch (JSONException e) { 
     Log.e("CommTest", e.getMessage()); 
    } 
    String js = String.format("window.plugins.appcomm.updateValues('%s');", 
     data.toString()); 
    this.sendJavascript(js); 
    } 
} 

import org.apache.cordova.api.Plugin; 
import org.apache.cordova.api.PluginResult; 
import org.json.JSONArray; 
import org.json.JSONException; 
import org.json.JSONObject; 

import android.util.Log; 

public class AppComm extends Plugin{ 

    private static AppComm instance; 

    public AppComm() { 
    instance = this; 
    } 

    public static AppComm getInstance() { 
    return instance; 
    } 

    @Override 
    public PluginResult execute(String action, JSONArray args, String callbackId) { 
    System.out.println("in execute from appcomm"); 


    return null; 
    } 

    public void sendValue(String value1, String value2) { 
    System.out.println("sendvalue in appComm"); 
    JSONObject data = new JSONObject(); 
    try { 
     data.put("value1", value1); 
     data.put("value2", value2); 
    } catch (JSONException e) { 
     Log.e("CommTest", e.getMessage()); 
    } 
    String js = String.format(
     "window.plugins.commtest.updateValues('%s');", 
     data.toString()); 
    this.sendJavascript(js); 
    } 
} 

RES/XML/plugins.xml

<plugins> 
    <plugin name="App" value="org.apache.cordova.App"/> 
    <plugin name="Geolocation" value="org.apache.cordova.GeoBroker"/> 
    <plugin name="Device" value="org.apache.cordova.Device"/> 
    <plugin name="Accelerometer" value="org.apache.cordova.AccelListener"/> 
    <plugin name="Compass" value="org.apache.cordova.CompassListener"/> 
    <plugin name="Media" value="org.apache.cordova.AudioHandler"/> 
    <plugin name="Camera" value="org.apache.cordova.CameraLauncher"/> 
    <plugin name="Contacts" value="org.apache.cordova.ContactManager"/> 
    <plugin name="File" value="org.apache.cordova.FileUtils"/> 
    <plugin name="NetworkStatus" value="org.apache.cordova.NetworkManager"/> 
    <plugin name="Notification" value="org.apache.cordova.Notification"/> 
    <plugin name="Storage" value="org.apache.cordova.Storage"/> 
    <plugin name="Temperature" value="org.apache.cordova.TempListener"/> 
    <plugin name="FileTransfer" value="org.apache.cordova.FileTransfer"/> 
    <plugin name="Capture" value="org.apache.cordova.Capture"/> 
    <plugin name="Battery" value="org.apache.cordova.BatteryListener"/> 
    <plugin name="SplashScreen" value="org.apache.cordova.SplashScreen"/> 

    <plugin name="AppComm" value="com.example.plugin.AppComm"/> 
</plugins> 

cordova.xml

<?xml version="1.0" encoding="utf-8"?> 
<cordova> 
    <access origin=".*"/> <!-- allow local pages --> 
    <log level="DEBUG"/> 
    <preference name="classicRender" value="true" /> 
</cordova> 

索引。html標頭

<head> 
    <meta charset="utf-8" /> 
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0" /> 
    <title> 
    </title> 
    <link rel="stylesheet" href="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.css" /> 
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"> 
    </script> 
    <script src="http://code.jquery.com/mobile/1.1.0/jquery.mobile-1.1.0.min.js"> 
    </script> 
    <script type="text/javascript" charset="utf-8" src="cordova.js"></script> 
    <script type="text/javascript" charset="utf-8"> 
    var AppComm=function(){}; 

    AppComm.prototype.updateValues=function(a){ 
    var map = new Object(); 
    map["X1"] = "hallo"; 
    map["X2"] = "hi"; 
    cordova.exec(null, null, null); 
    }; 

    cordova.addConstructor(function(){cordova.addPlugin("appcomm",new AppComm)}); 
    </script> 
</head> 

其中一個問題是,JavaScript是在一個單獨的文件(我認爲這是其中一個問題)。如果問題不多,我該如何正確地調用java回來,並用什麼值呢?如何實現execute方法以及如何調用它(我在JQuery中真的很糟糕)?

+0

你使用哪個版本的PhoneGap? – Shade 2013-04-10 12:49:57

+0

@Shade我正在使用科爾多瓦2.5.0 – stealthjong 2013-04-10 13:06:08

回答

9

首先,您正在使用Plugin子類。 Plugin已棄用,已換成CordovaPlugin。如果您使用的是舊版本的PhoneGap,我會建議您升級。

其次,你的exec調用是錯誤的。插件開發的文檔明確指出,當你傳遞3個空值時,你必須傳遞5個參數。你期望如何處理?

cordova.exec(function(winParam) {}, function(error) {}, "service", 
      "action", ["firstArgument", "secondArgument", 42, 
      false]); 

這裏,serviceaction和參數數組確定在Java代碼中會發生什麼。前兩個決定了在某些條件下JavaScript會發生什麼。所以,雖然前兩個可以使用null,但您必須指定最後三個。

我有一個工作示例插件,與PhoneGap 2.3.0一起使用。請參見下面的代碼:

public class ExampleJSCommunicator extends CordovaPlugin { 

    public boolean execute (final String action, final JSONArray args, CallbackContext callbackContext) throws JSONException { 
     PluginResult.Status status = PluginResult.Status.OK; 
     String result = ""; 

     cordova.getActivity().runOnUiThread (new Runnable() { 
      @Override 
      public void run() { 
       try { 
        String displayText = ""; 
        if (action.equals ("buttonClicked")) { 
         displayText = args.getString(0) + " was clicked"; 
        } 

        else if (action.equals ("animationRunning")) { 
         displayText = args.getBoolean(0) ? "Animation started running" : "Animation stopped running"; 
        } 

        TextView label = (TextView) cordova.getActivity().findViewById (R.id.textView); 
        label.setText (displayText + " and the Activity knows it!"); 
       } catch (JSONException e) { 
        e.printStackTrace(); 
       } 
      } 
     }); 

     return true; 
    } 
} 

通過上面的代碼,你有你的Java端插件能夠處理兩個自定義的「行動」 - buttonClickedanimationRunning。這些行爲符合我的目的,但您可以以其他方式命名。

現在,你仍然需要註冊你的插件,這樣科爾多瓦纔會知道它。這在xml/config.xml文件中完成。在plugins,你必須添加以下內容:

<plugin name="ExampleJSCommunicator" value="com.example.phonegap.ExampleJSCommunicator"/> 

然後你可以如下從JavaScript傳遞數據(或「行動」)。注意,參數(which.idanimationRunning在陣列中傳遞):

cordova.exec (null, null, "ExampleJSCommunicator", "buttonClicked", [which.id]); // my first action 
cordova.exec (null, null, "ExampleJSCommunicator", "animationRunning", [animationRunning]); // my second action 

這兩個exec呼叫將觸發ExampleJSCommunicator類的執行方法,並且如果塊將在各自得到處理。只要你在包含cordova.js文件後聲明你的JavaScript代碼,那麼你調用exec的位置並不重要。我的JavaScript被包含在一個單獨的main.js文件中,它工作得很好:

<script type="text/javascript" charset="utf-8" src="cordova.js"></script> 
<script type="text/javascript" charset="utf-8" src="main.js"></script> 
+0

對不起,我花了一段時間,但我一直在忙於其他事情,但你的榜樣給了我最終的努力,使它能夠雙向工作。這對我來說非常困惑,特別是放在哪裏(IE phonegap 1.7.1有2個xml,插件和cordova,以及你正在討論config.xml等等)。那謝謝啦。 – stealthjong 2013-04-13 09:03:20

+0

是的,它可能有點令人困惑 - 我花了幾個小時才讓它工作。很高興我可以幫助和感謝賞金:) – Shade 2013-04-13 15:27:39

+0

這是一個很好的插件如何工作的解釋,謝謝! – MBillau 2013-04-15 15:56:17

3

到目前爲止,您實際上並沒有使用Apache Cordova提供的任何工具來製作插件,只是試圖用標準的Android SDK來安裝一個類。如果您正在尋找添加功能,我建議編寫插件,是因爲以下幾個原因:

  • 的Apache科爾多瓦具有的WebView和Java之間的通信的替代方式,以便它可addJavascriptInterface失敗
  • 仍然有效,甚至你並不需要重寫的東西

我強烈建議你讀這和移動你的自定義Java代碼的插件:http://docs.phonegap.com/en/2.5.0/guide_plugin-development_android_index.md.html

但是,例如你的主要錯誤是使用您的類中的WebView而不是CordovaWebView。 WebView沒有可用的sendJavascript方法,發送Javascript的唯一簡單方法是使用loadUrl。

+0

謝謝,但你能再詳細一點嗎?看到我的補充。將示例代碼組合在一起,特別是插件中的execute()方法,我遇到了很多麻煩。 – stealthjong 2013-04-10 09:20:57

+1

@ChristiaandeJong這個文檔是足夠描述性的。只是讀它。不要在沒有閱讀文檔的情況下拼湊一些示例。 – Shade 2013-04-10 12:14:08

+0

@Shade我已經閱讀過它(多倍)。在我的代碼中,你會看到它接近指南。我將它拼湊在一起*使用文檔,但我無法完全掌握整個指南。 – stealthjong 2013-04-10 12:34:00