Thank you for the latest 1.3.0 release, it's motivated me to return to an unfinished project.
I have run into a problem using Webview I hope I can get some help with...
I am using a Webview and Javascript to provide a custom user interface. The Javascript code needs to get data from the Activity via an object made available to Javascript with Webview.addJavaScriptInterface() :
See
http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)(Despite the name of this method, the passed object does not require implementation of a Java Interface.)
For testing purposes I am targeting SDK 16 to remove the Java Annotation requirement from the mix.
I can successfully pass existing Java objects and access their methods from a Chrome Javascript console for the Webview:
See
https://developer.chrome.com/devtools/docs/remote-debugging#debugging-webviews... which is very cool btw!
For an instance of java.lang.String (mywebview_activity.rb):
@wv.add_javascript_interface java::lang::String.new("abc"), "jsi_string"
Javascript console results are as expected:
jsi_string.toString() #=> "abc"
jsi_string.length() #=> 3
jsi_string.toUpperCase() #=> "ABC"
But for instances of Ruby classes, with various attempts to specify their Java counterparts (mywebview_activity.rb):
class JSIRuby
java_signature "java.lang.String ok()"
def ok ; "ok" ; end
end
class JSIRubySubJava < java::lang::Object
java_signature "java.lang.String ok()"
def ok ; "ok" ; end
end
@wv.add_javascript_interface JSIRuby.new, "jsi_ruby"
@wv.add_javascript_interface JSIRubySubJava.new, "jsi_rubysubjava"
@wv.add_javascript_interface JSIRuby.new.to_java, "jsi_ruby_to_java"
@wv.add_javascript_interface JSIRubySubJava.new.to_java, "jsi_rubysubjava_to_java"
Some Java Object methods are accessible from Javascript:
jsi_ruby.toString() #=> "#<JSIRuby:0x3fd64234>"
jsi_ruby_tojava.toString() #=> "#<JSIRuby:0x1af07fd7>"
jsi_rubysubjava.toString() #=> "org.jruby.proxy.java.lang.Object$Proxy0@e176b18"
jsi_rubysubjava_tojava.toString() #=> "org.jruby.proxy.java.lang.Object$Proxy0@36a420c4"
But not the Ruby methods:
jsi_ruby.ok() #=> Uncaught TypeError: undefined is not a function
jsi_ruby_tojava.ok() #=> Uncaught TypeError: undefined is not a function
jsi_rubysubjava.ok() #=> Uncaught TypeError: undefined is not a function
jsi_rubysubjava_tojava.ok() #=> Uncaught TypeError: undefined is not a function
I also tried a Ruby class with explicit Java backing class:
ruboto gen subclass java.lang.Object --name=JSIJavaCustom --method_base=none
... created Java methods (JSIJavaCustom.java):
public java.lang.String ok() {
if (ScriptLoader.isCalledFromJRuby()) return "oops! - ScriptLoader.isCalledFromJRuby()";
if (!JRubyAdapter.isInitialized()) {
Log.i("Method called before JRuby runtime was initialized: JSIJavaCustom#ok");
return "oops! - !JRubyAdapter.isInitialized()";
}
String rubyClassName = scriptInfo.getRubyClassName();
if (rubyClassName == null) return "oops! - rubyClassName == null";
return (java.lang.String) JRubyAdapter.runRubyMethod(java.lang.String.class, scriptInfo.getRubyInstance(), "ok");
}
public java.lang.String ok_java() {
return "ok_java";
}
... created Ruby methods (jsi_java_custom.rb):
class JSIJavaCustom
java_signature "java.lang.String ok()"
def ok
"ok"
end
end
... passed an instance to the Webview (mywebview_activity.rb):
require_relative 'jsi_java_custom.rb'
@wv.add_javascript_interface JSIJavaCustom.new, "jsi_javacustom"
For Javascript console result:
jsi_javacustom.toString() #=> "#<JSIJavaCustom:0x33a028c6>"
jsi_javacustom.ok_java() #=> Uncaught TypeError: undefined is not a function
jsi_javacustom.ok() #=> Uncaught TypeError: undefined is not a function
...it seems that only the Java superclass methods are accessible.
I did all of the above with and without java_signature specified.
A final effort with .become_java! :
See
https://github.com/jruby/jruby/wiki/GeneratingJavaClasses...went nowhere fast:
# .newInstance() causes java.lang.InstantiationException: class org.jruby.RubyObject has no zero argument constructor
# @wv.add_javascript_interface (JSIRuby.become_java!).newInstance(), "jsi_ruby_become_java"
# .become_java! does not work for subclasses of Java classes : https://github.com/jruby/jruby/issues/2359
# @wv.add_javascript_interface (JSIRubySubJava.become_java!).new, "jsi_rubysubjava_become_java"
Right now I have no idea what else to try.
Have I missed something about Ruboto/JRuby to Java interfacing ?
Does the Android Webview require a specific Java-ism that Ruboto/JRuby interfacing does not provide ?
I will share a repo of this test app.
Thanks.
-gf-