Android Calling JavaScript functions in WebView - javascript

I am trying to call some javascript functions sitting in an html page running inside an android webview. Pretty simple what the code tries to do below - from the android app, call a javascript function with a test message, which inturn calls a java function back in the android app that displays test message via toast.
The javascript function looks like:
function testEcho(message){
window.JSInterface.doEchoTest(message);
}
From the WebView, I have tried calling the javascript the following ways with no luck:
myWebView.loadUrl("javascript:testEcho(Hello World!)");
mWebView.loadUrl("javascript:(function () { " + "testEcho(Hello World!);" + "})()");
I did enable javascript on the WebView
myWebView.getSettings().setJavaScriptEnabled(true);
// register class containing methods to be exposed to JavaScript
myWebView.addJavascriptInterface(myJSInterface, "JSInterface");
And heres the Java Class
public class JSInterface{
private WebView mAppView;
public JSInterface (WebView appView) {
this.mAppView = appView;
}
public void doEchoTest(String echo){
Toast toast = Toast.makeText(mAppView.getContext(), echo, Toast.LENGTH_SHORT);
toast.show();
}
}
I've spent a lot of time googling around to see what I may be doing wrong. All examples I have found use this approach. Does anyone see something wrong here?
Edit: There are several other external javascript files being referenced & used in the html, could they be the issue?

I figured out what the issue was : missing quotes in the testEcho() parameter. This is how I got the call to work:
myWebView.loadUrl("javascript:testEcho('Hello World!')");

From kitkat onwards use evaluateJavascript method instead loadUrl to call the javascript functions like below
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
webView.evaluateJavascript("enable();", null);
} else {
webView.loadUrl("javascript:enable();");
}

public void run(final String scriptSrc) {
webView.post(new Runnable() {
#Override
public void run() {
webView.loadUrl("javascript:" + scriptSrc);
}
});
}

I created a nice wrapper to call JavaScript methods; it also shows JavaScript errors in log:
private void callJavaScript(String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
for (int i = 0; i < params.length; i++) {
Object param = params[i];
if(param instanceof String){
stringBuilder.append("'");
stringBuilder.append(param.toString().replace("'", "\\'"));
stringBuilder.append("'");
}
if(i < params.length - 1){
stringBuilder.append(",");
}
}
stringBuilder.append(")}catch(error){Android.onError(error.message);}");
webView.loadUrl(stringBuilder.toString());
}
You need to add this too:
private class WebViewInterface{
#JavascriptInterface
public void onError(String error){
throw new Error(error);
}
}
And add this interface to your webview:
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(new WebViewInterface(), "AndroidErrorReporter");

Yes you have the syntax error. If you want to get your Javascript errors and printing statements in your logcat you must implement the onConsoleMessage(ConsoleMessage cm) method in your WebChromeClient. It gives the complete stack traces like Web console(Inspect element). Here is the method.
public boolean onConsoleMessage(ConsoleMessage cm)
{
Log.d("Message", cm.message() + " -- From line "
+ cm.lineNumber() + " of "
+ cm.sourceId() );
return true;
}
After implementation you will get your Javascript errors and print statements (console.log) on your logcat.

Modification of #Ilya_Gazman answer
private void callJavaScript(WebView view, String methodName, Object...params){
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("javascript:try{");
stringBuilder.append(methodName);
stringBuilder.append("(");
String separator = "";
for (Object param : params) {
stringBuilder.append(separator);
separator = ",";
if(param instanceof String){
stringBuilder.append("'");
}
stringBuilder.append(param.toString().replace("'", "\\'"));
if(param instanceof String){
stringBuilder.append("'");
}
}
stringBuilder.append(")}catch(error){console.error(error.message);}");
final String call = stringBuilder.toString();
Log.i(TAG, "callJavaScript: call="+call);
view.loadUrl(call);
}
will correctly create JS calls e.g.
callJavaScript(mBrowser, "alert", "abc", "def");
//javascript:try{alert('abc','def')}catch(error){console.error(error.message);}
callJavaScript(mBrowser, "alert", 1, true, "abc");
//javascript:try{alert(1,true,'abc')}catch(error){console.error(error.message);}
Note that objects will not be passed correctly - but you can serialize them before passing as an argument.
Also I've changed where the error goes, I've diverted it to the console log which can be listened by:
webView.setWebChromeClient(new CustomWebChromeClient());
and client
class CustomWebChromeClient extends WebChromeClient {
private static final String TAG = "CustomWebChromeClient";
#Override
public boolean onConsoleMessage(ConsoleMessage cm) {
Log.d(TAG, String.format("%s # %d: %s", cm.message(),
cm.lineNumber(), cm.sourceId()));
return true;
}
}

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<WebView
android:id="#+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import com.bluapp.androidview.R;
public class WebViewActivity3 extends AppCompatActivity {
private WebView webView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_web_view3);
webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new WebViewClient());
webView.getSettings().setJavaScriptEnabled(true);
webView.loadUrl("file:///android_asset/webview1.html");
webView.setWebViewClient(new WebViewClient(){
public void onPageFinished(WebView view, String weburl){
webView.loadUrl("javascript:testEcho('Javascript function in webview')");
}
});
}
}
assets file
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.0//EN" "http://www.wapforum.org/DTD/xhtml-mobile10.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>WebView1</title>
<meta forua="true" http-equiv="Cache-Control" content="max-age=0"/>
</head>
<body style="background-color:#212121">
<script type="text/javascript">
function testEcho(p1){
document.write(p1);
}
</script>
</body>
</html>

Here is an example to load js script from the asset on WebView.
Put script to a file will help reading easier
I load the script in onPageFinished because I need to access some DOM element inside the script (to able to access it should be loaded or it will be null). Depend on the purpose of the script, we may load it earlier
assets/myjsfile.js
document.getElementById("abc").innerText = "def"
document.getElementById("abc").onclick = function() {
document.getElementById("abc").innerText = "abc"
}
WebViewActivity
webView.settings.javaScriptEnabled = true
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
val script = readTextFromAsset("myjsfile.js")
view.loadUrl("javascript: $script")
}
}
fun readTextFromAsset(context: Context, fileName: String): String {
return context.assets.open(fileName).bufferedReader().use { it.readText()
}

Related

How to block a webpage advertisement when it is inside android studio Webview? [duplicate]

I want to implement a mechanism in a custom webview client (without JavaScript injection) that can block ads. Is a way I can catch ads and replace them with other ads from a trusted source?
Thanks
In your custom WebViewClient, you can override the function shouldInterceptRequest(WebView, WebResourceRequest).
From Android docs:
Notify the host application of a resource request and allow the application to return the data.
So the general idea is to check if the request is coming from an ad URL (plenty of black list filters out there), then return a "fake" resource that isn't the ad.
For a more in depth explanation plus an example, I recommend checking out this blog post.
To implement this, you have two options:
Use Javascript injected code to do this (which you explicitely said, don't want)
In WebView, instead of "http://example.com" load "http://myproxy.com?t=http://example.com" (properly escaped, of course) and setup "myproxy.com" to be a proxy which will fetch the upstream page (given in "t" query parameter, or in any other way) and replace ads with the trusted ones before sending response to the client. This will be pretty complex, though, because ads can be in many forms, they're usually Javascript injected themselves and you'd probably need to rewrite a lot of URL's in the fetched HTML, CSS and JS files etc.
I made a custom WebViewClient like:
public class MyWebViewClient extends WebViewClient {
#Override
public void onPageFinished(WebView view, String url) { }
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
if (url.endsWith(".mp4")) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse(url), "video/*");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
return true;
} else if (url.startsWith("tel:") || url.startsWith("sms:") || url.startsWith("smsto:")
|| url.startsWith("mms:") || url.startsWith("mmsto:")) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
view.getContext().startActivity(intent);
return true;
} else {
return super.shouldOverrideUrlLoading(view, url);
}
}
private Map<String, Boolean> loadedUrls = new HashMap<>();
#SuppressWarnings("deprecation")
#Override
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
boolean ad;
if (!loadedUrls.containsKey(url)) {
ad = AdBlocker.isAd(url);
loadedUrls.put(url, ad);
} else {
ad = loadedUrls.get(url);
}
return ad ? AdBlocker.createEmptyResource() :
super.shouldInterceptRequest(view, url);
}
}
And created an AdBlocker class like:
public class AdBlocker {
private static final Set<String> AD_HOSTS = new HashSet<>();
public static boolean isAd(String url) {
try {
return isAdHost(getHost(url));
} catch (MalformedURLException e) {
Log.e("Devangi..", e.toString());
return false;
}
}
private static boolean isAdHost(String host) {
if (TextUtils.isEmpty(host)) {
return false;
}
int index = host.indexOf(".");
return index >= 0 && (AD_HOSTS.contains(host) ||
index + 1 < host.length() && isAdHost(host.substring(index + 1)));
}
public static WebResourceResponse createEmptyResource() {
return new WebResourceResponse("text/plain", "utf-8", new ByteArrayInputStream("".getBytes()));
}
public static String getHost(String url) throws MalformedURLException {
return new URL(url).getHost();
}
}
And use this WebViewClient in your oncreate like:
webview.setWebViewClient(new MyWebViewClient());

Restoring Android WebView page with ViewModel after device rotation / split view

I use WebView to show data, the data gets augmented via JS function. It works fine until the device gets rotated. Using ViewModel to keep the page data and restore it after a config change seemed to be the right idea but I ran into problems, the page didn't get restored. I pared down my code to a minimalist example, included here (sans the XML layout)
DataStore class to store the data, overriding ViewModel, simply store some strings in a list
package com.automationce.labyrinth.webview;
import android.arch.lifecycle.ViewModel;
import java.util.ArrayList;
import java.util.List;
/* The idea is to use ViewModel to store page data
* so it can be restored on device rotate/split view */
public final class DataStore extends ViewModel {
public List<String> records = new ArrayList<>();
public DataStore() {
super();
}
}
Simple web view class, overriding WebView
package com.automationce.labyrinth.webview;
import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.webkit.WebView;
public final class SimpleWebView extends WebView {
// Use to keep and restore data between config changes
// (not related to browser history by any means)
private DataStore dataStore;
public SimpleWebView(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.LTGRAY);
getSettings().setJavaScriptEnabled(true);
setWebContentsDebuggingEnabled(true);
// Define style, write JS function(s)
String content = "<!DOCTYPE html><html><head>" +
"<style>" +
"span { font-size: " +
0.875 +
"em; } " +
"</style>" +
"</head><body id=\"body\">" +
jsFunctions() + "</body></html>";
loadDataWithBaseURL(null, content, "text/html", "utf-8", null);
}
// JS function(s) as written to the page
private String jsFunctions() {
return "<script>" +
"function append (string) { " +
"var body = document.getElementById('body');" +
"var block = document.createElement('span');" +
"var text = document.createTextNode(string);" +
"var br = document.createElement('br'); " +
"block.appendChild(text);" +
"block.appendChild(br); " +
"body.appendChild(block);" +
"block.scrollIntoView();" +
" }" +
"</script>";
}
public void setHistory (final DataStore storedData) {
dataStore = storedData;
}
// Restore page from DataStore data
public void restore() {
for(String record : dataStore.records) {
evaluateJavascript("append ('" + record + "');", null);
}
}
// Append new data to existing page
public void append(final String string) {
dataStore.records.add(string);
evaluateJavascript("append ('" + string + "');", null);
}
}
And finally the MainActivity itself
package com.automationce.labyrinth.webview;
import android.arch.lifecycle.ViewModelProviders;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private SimpleWebView pageView;
private Button appendButton;
private int counter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DataStore storedData = ViewModelProviders.of(this).get(DataStore.class);
appendButton = findViewById(R.id.button);
pageView = findViewById(R.id.webView);
pageView.setHistory(storedData);
pageView.restore();
appendButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
append();
}
});
}
private void append() {
counter++;
pageView.append("Some kind of new text " + counter);
}
}
The idea was to preserve the data in ViewModel and restore it during creation. It took me a while to figure why it doesn't work. DataStore does get preserved during rotation (I can see all the history data in the DataStore object) but although I see the restore code being executed, it never gets rendered in SimpleWebView.
The reason is that while JavaScript function does get correctly written to the page, I am calling restore() from MainActivity.OnCreate before the page actually renders. The JS function gets called and quickly ignored because the page, in reality, doesn't exist as far as WebView is concerned (I think). Surprisingly, this actually worked on the majority of simulators I use - now I think it shouldn't and I have no clue why it did - until I ran it on a physical device (Galaxy S7), where the restore was ignored
My solution was to give my SimpleWebView a new WebViewClient and override its OnPageFinished method and in it restore the content of the page after the page finishes loading. SimpleView constructor ('firstView' boolean flag in the code below gets invalidated after the view reloads for the first time after the device rotation):
public SimpleWebView(Context context, AttributeSet attrs) {
super(context, attrs);
setBackgroundColor(Color.LTGRAY);
getSettings().setJavaScriptEnabled(true);
setWebContentsDebuggingEnabled(true);
setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
Log.v("PAGE", "finished");
if (firstView) {
((SimpleWebView)view).restore();
}
}
});
.
.
The web page now gets reconstructed from the persistent data after device rotation/split window. It seems to work well, without any noticeable load delay (I am dealing with relatively small data set now).
I have looked for solutions, I really don't want to save and restore a String content of the whole page in OnSaveInstanceState / onRestoreInstanceState because in this case, it won't do me any good - I'll have the data but I still need to restore it after the page gets rendered
Words of wise I seek from the collective:
Is my analysis correct?
Are there better ways of handling this?
Is there something (an unpleasant production code surprise, etc. - I am pretty new to Android) for which I should be watching out?
Thanks, Jiri

Android WebView not returning desired HTML

so a quick overview of what I'm doing
I am using Android Webview to Render JavaScript and then reading the HTML from the javascript to parse it.
I am currently having trouble with retrieving the HTML from a website called Sport Chek.
Here is the code for my SportChekSearch class:
public class SportChekSearch extends SearchQuery{
public Elements finalDoc;
private ArrayList<Item> processed;
private final Handler uiHandler = new Handler();
public int status = 0;
//This basically is just so that the class knows which Activity we're working with
private Context c;
protected class JSHtmlInterface {
#android.webkit.JavascriptInterface
public void showHTML(String html) {
final String htmlContent = html;
uiHandler.post(
new Runnable() {
#Override
public void run() {
Document doc = Jsoup.parse(htmlContent);
}
}
);
}
}
/**
* Constructor method
* #param context The context taken from the webview (So that the asynctask can show progress)
*/
public SportChekSearch(Context context, String query) {
final Context c = context;
try {
final WebView browser = new WebView(c);
browser.setVisibility(View.INVISIBLE);
browser.setLayerType(View.LAYER_TYPE_NONE, null);
browser.getSettings().setJavaScriptEnabled(true);
browser.getSettings().setBlockNetworkImage(true);
browser.getSettings().setDomStorageEnabled(true);
browser.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
browser.getSettings().setLoadsImagesAutomatically(false);
browser.getSettings().setGeolocationEnabled(false);
browser.getSettings().setSupportZoom(false);
browser.getSettings().setUserAgentString("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");
browser.addJavascriptInterface(new JSHtmlInterface(), "JSBridge");
browser.setWebViewClient(
new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
#Override
public void onPageFinished(WebView view, String url) {
browser.loadUrl("javascript:window.JSBridge.showHTML('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');");
}
}
);
browser.loadUrl("https://www.sportchek.ca/search.html#q=" + query.replaceAll(" ", "+") + "&lastVisibleProductNumber=3");
browser.loadUrl(browser.getUrl());
final String link = browser.getUrl();
new fetcher(c).execute(link);
}
catch(Exception e){
e.printStackTrace();
}
//Get the link from the WebView, and save it in a final string so it can be accessed from worker thread
}
/**
* This subclass is a worker thread meaning it does work in the background while the user interface is doing something else
* This is done to prevent "lag".
* To call this class you must write fetcher(Context c).execute(The link you want to connect to)
*
*/
class fetcher extends AsyncTask<String, Void, Elements> {
Context mContext;
ProgressDialog pdialog;
public fetcher(Context context) {
mContext = context;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
pdialog = new ProgressDialog(mContext);
pdialog.setTitle(R.string.finding_results);
pdialog.setCancelable(false);
pdialog.show();
}
//This return elements because the postExecute() method needs an Elements object to parse its results
#Override
protected Elements doInBackground(String... strings) {
//You can pass in multiple strings, so this line just says to use the first string
String link = strings[0];
//For Debug Purposes, Do NOT Remove - **Important**
System.out.println("Connecting to: " + link);
try {
doc = Jsoup.connect(link)
.ignoreContentType(true)
.userAgent("Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36")
.timeout(10000)
.get();
finalDoc = doc.select("body section.product-grid-wrapper");
System.out.println(finalDoc.toString());
} catch (IOException e) {
e.printStackTrace();
}
return finalDoc;
}
#Override
protected void onPostExecute(Elements result) {
//This line clears the list of info in the Search activity
//I should probably be using a getter method but adapter is a static variable so it shouldn't matter
//parse seperates document into elements
//crunch results formats those elements into item objects
//I am saving the result of this to an ArrayList<Item> called "processed"
processed = crunchResults(result);
//For debug purposes, do NOT remove - **Important**
System.out.println(processed.size() + " results have been crunched by Sport Chek.");
//Adds all of the processed results to the list of info in Search activity
ClothingSearch.adapter.addAll(processed);
//For debug purposes, do NOt remove - **Important
System.out.println("Adapter has been notified by Sport Chek.");
//Closes the progress dialog called pdialog assigned to the AsyncTask
pdialog.dismiss();
ClothingSearch.adapter.notifyDataSetChanged();
SearchQueueHandler.makeRequest(mContext, processed, SearchQueueHandler.CLOTHING_SEARCH);
}
}
public ArrayList<Item> crunchResults(Elements e){
ArrayList<Item> results = new ArrayList<Item>();
try {
for (int i = 0; i < e.size(); i++) {
Element ele = e.get(i);
String link = "https://www.sportchek.ca" + ele.select(" a.product-grid__link").attr("href");
System.out.println("https://www.sportchek.ca" + ele.select(" a.product-grid__link").attr("href"));
String title = ele.select(" span.product-title-text").text();
String pricestring = ele.select(" span.product-price__wrap").text();
price = Double.parseDouble(pricestring.substring(pricestring.lastIndexOf("$")));
System.out.println(pricestring);
//*******************************************
String store = "Sport Chek";
//Adds the formatted item to an ArrayList of items
results.add(new Item(title, store, price, link));
//Prints the object's to String to console
//For debug purposes, do NOT remove - **Important
System.out.println(results.get(i).toString());
}
} catch (Exception a){
a.printStackTrace();
}
return results;
}
public int getStatus(){
return status;
}
}
The two relevant methods are doInBackground in my AsyncTask and the crunchResults method.
Here is the result I get from using Ctrl+Shift+I on the actual website (Desired Result):
But when running the above code and using a println here is the result that I get for the tag section class="product-grid-wrapper" :
<section class="product-grid-wrapper">
<ul data-module-type="SearchProductGrid" class="product-grid__list product-grid__list_quickview">
<!-- #product-grid__item-template -->
</ul>
</section>
Can anyone help me figure out why I am not getting my desired result?
All help is appreciated
EDIT: for this specific search that the println data was collected from, the link was https://www.sportchek.ca/search.html#q=men+coat&lastVisibleProductNumber=3
It looks like what you are actually getting is the actual html sent by the server, and that your 'desired result' is what the DOM looks like after the JavaScript runs.
Your 'actual' is what I see if I use "View Source" in Chrome, while your "desired result" is what I see if I use Chrome's DOM inspector.
On further inspection, I see that you are not actually getting the HTML from the browser, you are (indirectly) using JSoup's Connection object to get the HTML directly. Unfortunately, that's not going to run the Javascript.
Instead, you're going to have to get the HTML from the WebView after the JavaScript runs. For a possible way to do that, see How do I get the web page contents from a WebView?
Then, you give the HTML that you get from that to JSoup with
Jsoup.parse(html);

how to wait for return value from javascript in android and proceed

I am just a learner of Android since a week before, It might be a trivial for someone but this looks big for me as I am new to this. I searched a lot and couldn't found a straight forward question or solution. So, I dont want to spend much time in confusing and post my question here.
I am having a webview in my app, which loads a webpage. I placed a button "Generate" below webview and calling an JS function "saveData()" in that web webpage in that button's onclick. This function needs few seconds to execute and return its response based on the user's network connection speed. Then, I am showing "copy" button to copy the return value.
generate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
generate.setVisibility(View.GONE);
copy.setVisibility(View.VISIBLE);
webView.loadUrl("javascript:alert(saveData)"); // this function needs few seconds.
}
});
I am catching the return value of the JS function as follows, and setting the value of string "JsVal"
String JsVal;
public String getJsVal() {
return jsVal;
}
public void setJsVal(String jsVal) {
this.jsVal = jsVal;
}
webView.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onJsAlert(WebView view, String url, String message,JsResult result) {
Log.d("LogTag from js call method", message);
setJsVal(message);
result.confirm();
return true;
}
});
Here, copy button code is making text copied for paste to somewhere,
copy.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Toast.makeText(getApplicationContext(), " Copied", Toast.LENGTH_SHORT).show();
pb.setVisibility(View.GONE);
ClipboardManager myClipboard;
myClipboard = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
ClipData myClip;
myClip = ClipData.newPlainText("text", tVal);
myClipboard.setPrimaryClip(myClip);
}
});
Problem is, if I click the generate button, immediatly copy button is available. If I click on the copy button immediatly and paste in notes app, it shows null. If I copy after 2-3 secondes its not null.
I want to show copy button after the JS return value assigned to String variable "JsVal", untill I need to show nothing.
How to do this,
Try the following:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
copy.setVisibility(View.VISIBLE);
}
});
generate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
generate.setVisibility(View.GONE);
webView.loadUrl("javascript:alert(saveData)"); // this function needs few seconds.
}
});
You should do it using a AsyncTask in button's onClick.
You can take a look at this documentation, https://developer.android.com/reference/android/os/AsyncTask.html
change your code as follows,
generate.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
generate.setVisibility(View.GONE);
//copy.setVisibility(View.VISIBLE);
webView.loadUrl("javascript:alert(saveData)"); // this function needs few seconds.
AsyncTaskRunner runner = new AsyncTaskRunner();
runner.execute();
}
});
Also you need to add the following code to get the AsyncTask works.
private class AsyncTaskRunner extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
try {
if (getVal() == null) {
doInBackground(params);
}
} catch (Exception e) {
e.printStackTrace();
}
return "success";
}
#Override
protected void onPostExecute(String result) {
copy.setVisibility(View.VISIBLE);
}
#Override
protected void onPreExecute() {
}
#Override
protected void onProgressUpdate(String... text) {
}
}
This is the solution you need to implement and it should work as you expected.
You'll need to extend the onPageFinished method via WebViewClient:
webView.setWebViewClient(new WebViewClient()
{
#Override
public void onPageFinished(WebView view, String url) {
// Enable button
}
});
Try this
webView.setWebChromeClient(new WebChromeClient() {
#Override
public boolean onJsAlert(WebView view, String url, String message,JsResult result) {
Log.d("LogTag from js call method", message);
setJsVal(message);
result.confirm();
return true;
}
#Override
public void onProgressChanged(WebView view, int progress) {
if (progress == 100) {
generate.setVisibility(View.GONE);
copy.setVisibility(View.VISIBLE);
}
}
});

How to send data from activity to a webview in that activity itself?

From this Activity I am sending data to another activity
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final EditText etxt=(EditText)findViewById(R.id.editText1);
final EditText etxt1=(EditText)findViewById(R.id.editText2);
Button btn=(Button)findViewById(R.id.button1);
btn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
String s= etxt.getText().toString();
String s1= etxt1.getText().toString();
Intent intent= new Intent(getApplicationContext(),WebActivity.class);
intent.putExtra("key", s);
intent.putExtra("key1", s1);
}
});
}
}
My second activity where i receive the data from intent and want to display it in the webview.
public class WebActivity extends Activity {
WebView webView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webpage);
Bundle b = getIntent().getExtras();
String s = b.getString("key");
String s1=b.getString("key1");
webView=(WebView)findViewById(R.id.webview);
}
}
From some searching on Google i found that it can be accomplished by using javascript variables but I dont know how to do it. Kindly answer.
Did you checked Android WebView documentation?
// Simplest usage: note that an exception will NOT be thrown
// if there is an error loading this page (see below).
webview.loadUrl("http://slashdot.org/");
// OR, you can also load from an HTML string:
String summary = "<html><body>You scored <b>192</b> points.</body></html>";
webview.loadData(summary, "text/html", null);
// ... although note that there are restrictions on what this HTML can do.
// See the JavaDocs for loadData() and loadDataWithBaseURL() for more info.
You can simply add your data in webview by
webview.loadData("your string text", "text/html", null);

Categories