How can I call a native function from cordova/phonegap webview for example for showing an ad.
EDIT: OK I FUNALLY GOT IT and I'm gonna write some steps for all of you who don't know how to do that (just to spare 2 days of your lifetime :D)
A) if you have just cordova/phonegap and and wish to call from js do this:
1) Replace the following code with your existing DroidGap Activity.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.init(); // Calling this is necessary to make this work
appView.addJavascriptInterface(this, "MainActivity");
/* "this" points the to the object of the current activity. "MainActivity" is used to refer "this" object in JavaScript as in Step 3. */
super.loadUrl("file:///android_asset/www/index.html");
}
2) Add the custom function in current (this) activity as following.
#JavascriptInterface
public void customFunctionCalled() {
Log.e("Custom Function Called", "Custom Function Called");
}
3) Now call this function from your HTML/JavaScript code as following.
window.MainActivity.customFunctionCalled();
B.1) if you have cordova/phonegap implemented in a webview and wish to call from js do this:
(and want to call normal function)
1) Add this to the main java file:
JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");
2) Declare the class JavaScriptInterface:
public class JavaScriptInterface {
private Activity activity;
public JavaScriptInterface(Activity activiy) {
this.activity = activiy;
}
#JavascriptInterface
public void showLog(){
Log.v("blah", "blah blah");
}
}
3) Call it from js with `window.JSInterface.showLog();
B.2) if you have cordova/phonegap implemented in a webview and wish to call from js (and want to call UI function, like a toast) do this:
1) Add this to the main java file:
JavaScriptInterface jsInterface = new JavaScriptInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInterface, "JSInterface");
2) Declare the class JavaScriptInterface:
public class JavaScriptInterface {
private Activity activity;
public JavaScriptInterface(Activity activiy) {
this.activity = activiy;
}
#JavascriptInterface
public void myFunction()
{
activity.runOnUiThread(new Runnable() {
public void run() {
//Code that interact with UI
showToast();
}
});
}
}
3) Add the toast function underneath:
public void showToast(){
Toast.makeText(getApplicationContext(), "this is my Toast message!!! =)",
Toast.LENGTH_LONG).show();
}
4) Call it with `window.JSInterface.myFunction();
As you see if you need a function that uses the UI you need to wrap your function into activity.runOnUiThread so that it can get called from js.
*If you want to call from java a jquery method do this:
Java:
cordova_webview.loadUrl("javascript:window.functionn()");
Javascript:
window.function = punish;
Have a nice day!
In the .java file
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.init(); // Calling this is necessary to make this work
appView.addJavascriptInterface(this, "MainActivity");
super.loadUrl(Config.getStartUrl());
}
In the javascript
window.MainActivity.customFunctionCalled();
This will only work on TargetSDK<17 . An androidManifest.xml targetSDK need to be set < 17. And for TargetSDK >=17 , I guess you'll need to create some custom plugin. I use this process lowering my target SDK for now.
Related
I'm displaying a webpage in my Android app using a WebView, this webpage triggers a window message event and gives some data through that event. I need to access the data from the message event.
To achieve this, I'm adding the JavaScript event listener by using evaluateJavascript() method and trying to call a Java function from the JavaScript using addJavascriptInterface().
My Code so far:
public class MyActivity extends AppCompatActivity {
#Override
#SuppressLint("SetJavaScriptEnabled")
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
WebView webView = new WebView(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setDomStorageEnabled(true);
webView.addJavascriptInterface(new JsObject(this), "Android");
webView.evaluateJavascript("window.addEventListener('message', (e) => {Android.logData('Test String')})", null);
webView.loadUrl("https://example.com/mypage");
setContentView(webView);
}
private class JsObject {
Context context;
JsObject(Context context) {
this.context = context;
}
#JavascriptInterface
public void logData(String s) {
Log.v("EEE", s);
}
}
}
But the event handler is not getting called. I'm not sure whether this is the right approach. Please help. TIA.
Switch the order of your loadUrl and evaluateJavascript calls. The loadUrl is resetting that state. Note: this may require changing the code on the page to avoid a race condition triggering the message.
From the evaluateJavascript docs:
global variables and functions defined before calling loadUrl(java.lang.String) will not exist in the loaded page
I am using webview in my application to show canvas. On my webview there is click here button. I want to open new activity on click of this 'click here' button on webview. I dont know how to handle this click event.Need help as soon as possible.
Following is my webview class code:
public class TableWebView extends Activity {
private SharedPreferences sharedPreferences;
private String customer_id,hotel_id;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_table_web_view);
WebView wvtable= (WebView)findViewById(R.id.webViewTable);
wvtable.setWebViewClient(new MyViewClient());
WebSettings webSettings = wvtable.getSettings();
webSettings.setJavaScriptEnabled(true);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
customer_id = sharedPreferences.getString("cust_id", "0");//if no customerid found automatically 0 will be used
hotel_id=sharedPreferences.getString("hotel_master_id","0");
wvtable.loadUrl("http://192.168.100.169/zoilo_admin/public/index.php/show-hotel-view?hotel_id="+hotel_id+"&customer_id="+customer_id+"&date_time="+ Util.selected_date_time);
}
And here is how it looks after opening that url in webview:
Binding JavaScript code to Android code
When developing a web application that's designed specifically for the WebView in your Android application, you can create interfaces between your JavaScript code and client-side Android code. For example, your JavaScript code can call a method in your Android code to start activity.
To bind a new interface between your JavaScript and Android code, call addJavascriptInterface(), passing it a class instance to bind to your JavaScript and an interface name that your JavaScript can call to access the class.
Caution: If you've set your targetSdkVersion to 17 or higher, you must add the #JavascriptInterface annotation to any method that you want available to your JavaScript (the method must also be public). If you do not provide the annotation, the method is not accessible by your web page when running on Android 4.2 or higher.
public class TableWebView extends Activity {
private SharedPreferences sharedPreferences;
private String customer_id,hotel_id;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_table_web_view);
WebView wvtable= (WebView)findViewById(R.id.webViewTable);
wvtable.setWebViewClient(new MyViewClient());
wvtable.addJavascriptInterface(new WebAppInterface(this), "Android");
WebSettings webSettings = wvtable.getSettings();
webSettings.setJavaScriptEnabled(true);
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
customer_id = sharedPreferences.getString("cust_id", "0");//if no customerid found automatically 0 will be used
hotel_id=sharedPreferences.getString("hotel_master_id","0");
wvtable.loadUrl("http://192.168.100.169/zoilo_admin/public/index.php/show-hotel-view?hotel_id="+hotel_id+"&customer_id="+customer_id+"&date_time="+ Util.selected_date_time);
}
public class WebAppInterface {
Context mContext;
/** Instantiate the interface and set the context */
WebAppInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public void startNewActivity() {
//startActivity(new Intent(this, youactivityname.class));
}
}
This creates an interface called Android for JavaScript running in the WebView. At this point, your web application has access to the WebAppInterface class. For example, here's some HTML and JavaScript that call your "startNewActivity" method of your class using the new interface when the user clicks a button:
<input type="button" value="Click Here" onClick="showActivity()" />
<script type="text/javascript">
function showActivity() {
Android.startNewActivity();
}
</script>
1. Javascript file ------ calls -------> CORDOVA PLUGIN(plugin.java)
2. CORDOVA PLUGIN(plugin.java) file -------calls-------> Android BroadcastReceiver file(Broadcast_Receiver.java)
Broadcast_Receiver.java contains onResume.
How do I call/initiate it from Javascript file?
Please see sample code at the bottom
Problem #1: I can't combine plugin.java & Broadcast_Receiver.java because they are extending CordovaPlugin & WLDroidGap respectively.
Problem #2: When I navigate between pages of my worklight application; onResume of Broadcast_Receiver.java never gets triggered because onResume is in native Android code
Possible solution which i was unable to implement:
use cordova onResume i.e.: document.addEventListener("resume", function() { });
merge plugin.java & Broadcast_Receiver.java
In short: how to initiate android lifecycle using a Cordova plug-in?
Sample code
Javascript file calls plugin
//some code
currentPage.myfunction= function() {
cordova.exec(Success, Failure, "plugin","someMETHOD", []);
}
plugin.java
public class plugin extends CordovaPlugin
{
//some code
float value= Broadcast_Receiver.Variable_Name;
//some code
}
Broadcast_Receiver.java
public class roamingadvisor extends WLDroidGap {
//some code
onCreate(){}
onResume(){}
onPause(){}
//some code
}
What I am trying to achieve
My application starts calculating data usage once it receives broadcast that data got activated
I am able to calculate data usage
It gets updated once i press home button & relaunch my app(i.e. trigger native onResume in android)
But when i keep using my application (i.e navigate between UI screen) native android onResume never gets triggered
Or
should i do it using entirely different approach?
*******R&D *******
I used below two link
https://apache.googlesource.com/cordova-android/+/2.6.x/framework/src/org/apache/cordova/Device.java
https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java
and wrote follwing code for my need
public class Myclass extends CordovaPlugin {
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
boolean multitasking=true;
BroadcastReceiver mReceiver=null;
//constructor
public MyDataUsage(){
}
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
//Device.uuid = getUuid();
this.initReceiver();
}
#Override
public void onPause(boolean multitasking) {
super.onPause(multitasking);
this.cordova.getActivity().unregisterReceiver(this.mReceiver);
}
#Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
this.cordova.getActivity().registerReceiver(this.mReceiver, intentFilter);
}
public void onDestroy() {
this.cordova.getActivity().unregisterReceiver(this.mReceiver);
}
private void initReceiver() {
this.mReceiver=new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
ctb=context;
if (intent.getAction().equals("android.net.conn.CONNECTIVITY_CHANGE"))
{
//My code
}
}
}
};
this.cordova.getActivity().registerReceiver(this.mReceiver, intentFilter);
}
public boolean execute(String action, JSONArray arr,
final CallbackContext callbackcontext) throws JSONException {
if (action.equals("getDataUsage")) {
try {
//code
callbackcontext.success(""+dataUsed+ ":" +timeElapsed+":"+StartTime);
} catch (Exception e) {
callbackcontext.error("ERROR :");
}
return true;
}
return false;
}
}
But onPause & onResume still gets called only when i press HOME key & RELAUNCH my APP
Should i CONCLUDE that " I can not implement ACTIVITY LIFECYCLE while naviagting in my UI/html SCREEN/pages" ???
By default Cordova application consist of a single Activity which hosts a single WebView. When you're navigating pages/changing content in web you will not get any lifecycle events from Activity because technically you're still in a context of a same Activity.
Note that CordovaPlugin class has callbacks for many Activity lifecycle methods, you can leverage them (https://github.com/apache/cordova-android/blob/master/framework/src/org/apache/cordova/CordovaPlugin.java). For example use initialize() method for starting your calculation and onDestroy() method to detect when your app is being closed. You can also use other CordovaPlugin methods such as onResume() and onPause() according to the logic you're trying to implement.
I need to detect from a native JAVA (non phonegap plugin) class if phonegap's web view has finished loading. Is this possible, or will I need to rely on structuring my code as a plugin?
I finally found a solution (tested and works).
It's a tricky workaround but does the job.
Step 1:
Create a new class in the same package as your MainActivity like this:
public class MyClass{
private WebView appView;
public MyClass(DroidGap gap, WebView view){
appView = view;
}
public void onLoaded(){
// This will be called when webview loaded
System.out.println("WORKED!!");
}
}
Step 2:
Add the following lines to the very end of onCreate() in your MainActivity:
MyClass ai = new MyClass(this, super.appView);
super.appView.addJavascriptInterface(ai, "MyClass");
It should look something like this:
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
super.loadUrl("file:///android_asset/www/index.html");
MyClass ai = new MyClass(this, super.appView);
super.appView.addJavascriptInterface(ai, "MyClass");
}
Step 3:
In your JavaScript code in assets/www add this:
document.addEventListener("deviceready", function(){
try{
// Might throw an error but onLoaded() gets called correctly
window.MyClass.onLoaded();
}
catch(e){
console.error(e)
}
});
Important: Make sure that cordova.js is correctly included in your index.html
This did the job for me.
I'm trying to launch an Activity when clicking a link inside a WebView component.
My Webview is loaded inside Main.java and I would like to launch SubActivity.java when clicking a link inside the Website which is in Main.java?
Also, how can I pass parameters to this activity?
Example: inspection://Project/1
"Inspection" is the name of my application, inspection is the Activity I would like to launch and 1 is the ID I would like to have.
You could use WebView's addJavaScriptInterface to allow JavaScript to control your application (in this case, to allow JavaScript to fire an Intent when a link is clicked).
To do this you need to pass a class instance to bind to JavaScript, this could be something like the following:
private final class JsInterface {
public void launchIntent(final String payload) {
Activity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
// use the payload if you want, attach as an extra, switch destination, etc.
Activity.this.startActivity(new Intent(Activity.this, SomeOtherActivity.class));
}
});
}
}
Then you add that to the WebView with something along these lines:
webView.addJavascriptInterface(js, "Android");
Then in JavaScript from the WebView you just use your new "Android" object's "launchIntent" method.
One option is to override the URL loading of the web view and pick up the click you want to launch the new activity. Check out the use of a subclassed WebViewClient in the docs:
http://developer.android.com/resources/tutorials/views/hello-webview.html
Another option is to bind your activity to a custom URL scheme. It's pretty common in doing client side OAuth, frequently through the browser instead of a WebView, but it should work similarly enough. There's a full example here:
https://github.com/brione/Brion-Learns-OAuth
Which shows how to bind the url scheme handler as well as handling getting launched via the Intent it generates (see onResume() in OAUTH.java).
First Add javascript method on your webpage's button onclick()
The function defined below..
function showAndroidToast(toast) {
AndroidFunction.showToast(toast);
}
Android Code is here for javascript Interface..
public class MyJavaScriptInterface {
Context mContext;
private Activity activity;
public MyJavaScriptInterface(Activity activiy) {
this.activity = activiy;
}
#JavascriptInterface
public void showToast(String toast){
Intent i=new Intent(getApplicationContext(), Subactivity.class);
i.putExtra("data", "tosecondActivity");
startActivity(i);
}