admin管理员组

文章数量:1180493

I have been working on a PhoneGap plugin to enable WebGL, intended for publishing HTML5 games to mobile. It's called WebGLGap. However, PhoneGap's way of calling plugin code (via exec) typically involves stringifying all the parameters to JSON, then parsing it on the other side again. According to this question, this has not changed even in PhoneGap 2.2 which was advertised as having a faster bridge. For something like WebGL, this is absolutely untenable and kills performance (<10 FPS) even for simple demos. This is because in many cases, especially 2D games, every frame must transmit a large block of JSON data representing all the WebGL commands to run. This includes all vertex data - imagine a huge string of "0.959455, 0.959595, 0.588575, 0.585858..." etc every frame.

Obviously stringifying and parsing is an unnecessary and inefficient step, but I'm struggling to find a way to pass the JSON data from JS to native which avoids that. Ideally this should work on both Android and iOS, but I'm happy to stick to an Android-only solution for now. Does anyone have any ideas about the most efficient way to do this?

I have been working on a PhoneGap plugin to enable WebGL, intended for publishing HTML5 games to mobile. It's called WebGLGap. However, PhoneGap's way of calling plugin code (via exec) typically involves stringifying all the parameters to JSON, then parsing it on the other side again. According to this question, this has not changed even in PhoneGap 2.2 which was advertised as having a faster bridge. For something like WebGL, this is absolutely untenable and kills performance (<10 FPS) even for simple demos. This is because in many cases, especially 2D games, every frame must transmit a large block of JSON data representing all the WebGL commands to run. This includes all vertex data - imagine a huge string of "0.959455, 0.959595, 0.588575, 0.585858..." etc every frame.

Obviously stringifying and parsing is an unnecessary and inefficient step, but I'm struggling to find a way to pass the JSON data from JS to native which avoids that. Ideally this should work on both Android and iOS, but I'm happy to stick to an Android-only solution for now. Does anyone have any ideas about the most efficient way to do this?

Share Improve this question edited May 23, 2017 at 10:27 CommunityBot 11 silver badge asked Nov 19, 2012 at 18:40 AshleysBrainAshleysBrain 22.6k16 gold badges91 silver badges125 bronze badges 4
  • Are you looking for a pratical solution? I wanted to give this a shot, but today I might not be able to, only tomorrow ... – fableal Commented Nov 27, 2012 at 18:06
  • "pratical" as in, with working code :) – fableal Commented Nov 27, 2012 at 18:11
  • Only have a sugestion, wondered if there was a way to create a websocket connection between the two, webql, js to the natvie app. – Emile Commented Nov 27, 2012 at 18:12
  • did you consider just wrapping the data in json-p callback functions? – technosaurus Commented Nov 28, 2012 at 1:26
Add a comment  | 

6 Answers 6

Reset to default 12 +500

Linkedin use Web Sockets for their iPad app. Might be worth looking into: http://engineering.linkedin.com/mobile/linkedin-ipad-nativeweb-messaging-bridge-and-websockets

Some of the benefits that you're looking for

  • WebSockets can communicate asynchronously from JavaScript to native.
  • WebSockets don't have a payload limit
  • WebSockets don't require us to encode our JSON strings as URL parameters
  • WebSockets should be faster than URL scheme navigation

Addressing performance

Looking at CordovaPlugin.java, as you mentioned, everything is a String:

public boolean execute(String action, String rawArgs, CallbackContext callbackContext) throws JSONException {
    JSONArray args = new JSONArray(rawArgs);
    return execute(action, args, callbackContext);
}

If, for example, the conversion from String to JSONArray is the only bottleneck, then you could override this method in your plugin and perform your own deserialization. It's a small performance improvement, but it might be worth investigating.

Creating an alternate bridge

As for creating an alternative bridge, that's trickier. I don't know much about Cordova / PhoneGap, but from what research I've gathered, Cordova exposes a specific Javascript interface via addJavascriptInterface. If you could implement your own NativetoJSMessageQueue, you might be able to wire it all together.

EDIT
After conducting a bit more research, I can provide a bit more direction. The really relevant part of the NativetoJSMessageQueue is the various BridgeModes it implements (see line 92). You could look at the other bridge modes as an example.

Unfortunately, the NativetoJSMessageQueue has exactly four bridge modes registered; assuming that you could implement your own bridge mode, you would still need to some how register it as a new mode for the NativetoJSMessageQueue.

I'm not sure what exactly you want to do but I notice that in your project you are converting the JSON to String and then you will pass it through the PhoneGap plugin , convert it to JSON and then convert it to Matrix!

what if you keep your data in a string and convert the string straight to Matrix? this way you can skip the converting to and from JSON part

On android, you can try to use the addJavascriptInterface (link to WebView's documentation) method of the WebView to "inject Java objects into the WebView", which is the approach PhoneGap uses to add the apis for geolocation, filesystem, etc.

I guess this will be faster than using the plugin approach (didn't test this yet).

Check the code of the PhoneGapView, which extends WebView: https://github.com/phonegap/phonegap/blob/3c7324ea8b3944b6e5d3d91e9e328c9c3939464b/android/framework/src/com/phonegap/PhoneGapView.java#L42

UPDATE

After all, this only works for simple types such as int or String, like you said in a comment below.

Passing a JavaScript object using addJavascriptInterface() on Android

Trying to do otherwise will result in exceptions from within the android.webkit.WebViewCore and android.webkit.JWebCoreJavaBridge classes.

UPDATE 2

Well, the best code you'll achieve using this approach will be something like this (from https://github.com/commonsguy/cw-advandroid/blob/master/WebView/GeoWeb1/src/com/commonsware/android/geoweb/GeoWebOne.java#L80):

public String getLocation() throws JSONException {
  Location loc=myLocationManager.getLastKnownLocation(PROVIDER);

  if (loc==null) {
    return(null);
  }

  JSONObject json=new JSONObject();

  json.put("lat", loc.getLatitude());
  json.put("lon", loc.getLongitude());

  return(json.toString());
}

and most likely, all parameters should be string'fied (or JSON'fied...)

This might help you if you have a performance hit when triying to create strings from javascript side: http://www.javascripture.com/ArrayBuffer

I've read about encoding data in png. Here is the original article: http://cg.alexandra.dk/2012/11/26/webgl-tutorial-optimizing-data-transfer-for-webgl-applications/

Might be useful.

Given that json is very inefficient, you may gain a lot of performance if you take this route:

server side: data model -> protobuf (build() to binary) -> encode base64 (binary to string) -> add as one json field or payload (best is to pass binary blob as a payload, but I'm not sure if PhoneGap allow this)

client side: decode from base64 (string to binary) -> protobuf (parse from binary) -> use the protobuf objects directly as deep as you can in your code - it's extremely efficient data model

本文标签: javascriptPhoneGap plugin fastest way to transfer JSON data to nativeStack Overflow