Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Webcontainer => Jasonette IPC #164

Open
gliechtenstein opened this issue Aug 10, 2017 · 14 comments
Open

Webcontainer => Jasonette IPC #164

gliechtenstein opened this issue Aug 10, 2017 · 14 comments
Assignees

Comments

@gliechtenstein
Copy link
Contributor

Should work the same way it works for the iOS branch

Jasonette/JASONETTE-iOS#253

@maks
Copy link
Contributor

maks commented Aug 11, 2017

@gliechtenstein I'm happy to work on this as I've just done the work on #162 so am in the webview head space atm.

@gliechtenstein
Copy link
Contributor Author

@maks sounds great! 👍👍

@maks
Copy link
Contributor

maks commented Aug 11, 2017

This will be implemented per the doc issue: Jasonette/documentation#66

@maks
Copy link
Contributor

maks commented Aug 11, 2017

@gliechtenstein I've got an initial working implementation: maks@5ed6938

BUT I haven't done the PR yet due to the interface for objects added to a Webview in Android via addJavaInterface() only allowing simple types we need to pass the Jason from Webview JS to Java via JSON string (JSON.stringify()) not an actual JS object. Would you be able to do it this way on iOS to be consistent?

@gliechtenstein
Copy link
Contributor Author

@maks I was thinking about that issue too. I guess we could do that in the worst case, but it feels a bit too inconvenient because then the user would have to write the code in escaped JSON string everytime and it's really cumbersome and not intuitive.

Would it be possible to inject an additional javascript on the Android side so that it automatically interprets a JS object into a JSON string before evaluating?

@maks
Copy link
Contributor

maks commented Aug 13, 2017

@gliechtenstein I guess we can load a bit of JS shim code to do this as long as we DONT target N where this will no longer work, [per this compatibility note](https://developer.android.com/reference/android/webkit/WebView.html#evaluateJavascript(java.lang.String, android.webkit.ValueCallback<java.lang.String>))

The problem with doing the above is we permentantly stop Jasonette from ever targeting Android N or higher.

An alternative to that is to require webcontainer content that wants to use JASON to do so via loading a JS library (eg. via CDN or locally) which could then hide this and any other future compatibility issues.

@maks
Copy link
Contributor

maks commented Aug 21, 2017

@gliechtenstein I saw you merged the iOS implementation for this. Are you ok then for me todo PR with implementation I have for Andriod with the caveat of needing to stringify() the return value?

@gliechtenstein
Copy link
Contributor Author

Oops sorry i totally dropped the ball on this one, shouldn't have merged that iOS one before this issue was resolved in this world. Thankfully an API doesn't exist until it's documented so I think we have some room for now.

An alternative to that is to require webcontainer content that wants to use JASON to do so via loading a JS library (eg. via CDN or locally) which could then hide this and any other future compatibility issues.

Could you elaborate a bit on this? Do you mean like injecting some JavaScript into the webview? And how is this different from the JS shim approach? I guess I didn't fully understand the JS shim approach to begin with...

@maks maks self-assigned this Aug 22, 2017
@maks
Copy link
Contributor

maks commented Aug 22, 2017

@gliechtenstein no worries.
What I meant would be to have content in a webview include a js file:
<script src="https://jasonette.org/webview-shim.js"></script>

and then webview-shim.js would expose whatever API we are going to document and the JS code in that would take care of doing anything needed to make it compatible across iOS and ANdroid, eg. needing to stringify() on Android.
Hope that makes sense?

@gliechtenstein
Copy link
Contributor Author

@maks I think this is kind of related to Jasonette/Jasonette#4 we're discussing. I guess now that we're going to be injecting JS files into JS execution context I guess there's not much holding us back from doing it this way?

@maks
Copy link
Contributor

maks commented Aug 23, 2017

@gliechtenstein no sorry its different, there we are talking about a webview whos content jasonette "controls" whereas here its any html content supplied be the user.

@gliechtenstein
Copy link
Contributor Author

@maks OK I've just realized my confusion stems from the fact that the anchor tag part of the link you pasted is broken and simply opens up at the top of the https://developer.android.com/reference/android/webkit/WebView.html page. I didn't understand because I didn't realize you were talking about the valueCallback part specifically.

Anyway, now that I understand I can make a more constructive comment hopefully.

Basically the way I've implemented this logic on iOS side is

  1. Create a javascript function called JASON.call and inject it to the webview context

  2. Instead of having JASON.call run some JS-to-native binding logic, the JASON.call simply creates an <iframe> element with its src attribute set to the JSON object parameter we pass in to JASON.call https://github.com/Jasonette/JASONETTE-iOS/pull/253/files#diff-f22c800ecb5b9ecf974c06bdcb66ad7cR1881

    NSString *summon = @"var JASON={call: function(e){var n=document.createElement(\"IFRAME\");n.setAttribute(\"src\",\"jason:\"+JSON.stringify(e)),document.documentElement.appendChild(n),n.parentNode.removeChild(n),n=null}};";
    [webView stringByEvaluatingJavaScriptFromString:summon];
    

    This JS creates an iframe that looks like this:

    <iframe src="jason://{\"trigger\": \"some_action\"}">
    

    (Note that we also make sure the iframe is cleaned up after this function is triggered. If you look at the script it calls removeChild to get rid of the created iframe right after execution)

  3. Then we make sure the webview monitors a URL navigation event. When we encounter a url request attempt that starts with jason://, we extract out the JSON and parse it into dictionary and use it: https://github.com/Jasonette/JASONETTE-iOS/pull/253/files#diff-f22c800ecb5b9ecf974c06bdcb66ad7cR1886

Basically iOS has the same challenge as the challenge you brought up for higher version Androids. There is no way to directly make native calls from webview, and this is how we achieve it.

And since this problem is not unique to Android, I was thinking maybe we could do the same thing for Android.

  1. Create a similar JS logic and inject it into webview, like we do for iOS
  2. Implement shouldOverrideUrlLoading and watch out for the jason:// url, and when we come across one, parse it into JSONObject and use it.

How does that sound?

@maks
Copy link
Contributor

maks commented Sep 4, 2017

@gliechtenstein sorry about the broken link. I think we may have our wires crossed here...

On Android you can just "native calls" into Java directly. You use addJavascriptInterace() to inject a Java object into the global JS scope of the webview, then html content can call public methods of that object, there is no need at all for the iframe dance you need to use on iOS.

BUT there are constraints on the above, one of them is that the public Java methods you expose can only have "primitives" as parameter types, so you can pass in only numbers, strings, booleans but not JS objects. Hence the need to JSON.stringify().

So on Android its very straightforward to inject a Java object named JASON into the webviews global JS scope, its just not possible to pass it a object as a parameter, but a json string is fine.

To be honest to my mind this seems like a very small requirement to place on anyone making use of this interface, its just it would be nice for it to be consistent across iOS and Android.

@lehha
Copy link

lehha commented Aug 11, 2018

Will there are any solution to do calls from JS to JASON?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants