setJavaScriptEnabled(true) in 'doInBackground' override force closes app - javascript

I have followed this very basic example tutorial for loading a URL in a WebView async:
android-asynctask-example.
However the app force closes when i click 'Load Webpage', with the error:
"Can't create handler inside thread that has not called
Looper.prepare()".
When I remove the line "webView.getSettings().setJavaScriptEnabled(true);", the app works fine, and displays a WebView (obviously with no JavaScript enabled in the WebView).
If i leave that line in, but set enabled to false, the app also works without crashing.
I wish to modify this project, however i need JavaScript enabled, so was wondering if anyone had a clue as to why it was failing?
Any help will be greatly appreciated!

Try it this way,
public class MainActivity extends Activity {
final Context context = this;
WebView webView =null;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
private class LoadWebPageASYNC extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute(String result) {
webView = (WebView) findViewById(R.id.webView);
webView.getSettings().setJavaScriptEnabled(true);
}
#Override
protected String doInBackground(String... urls) {
webView.loadUrl(urls[0]);
return null;
}
#Override
protected void onPostExecute(String result) {
}
}
public void dummyFunc(View view){
Toast.makeText(MainActivity.this, "Button Clicked", Toast.LENGTH_SHORT).show();
}
public void readWebpage(View view) {
LoadWebPageASYNC task = new LoadWebPageASYNC();
task.execute(new String[] { "http://www.javacodegeeks.com" });
}
}

Related

Call MainActivity method from another class in android

I'm working on an android app. I want to pass some value from my webview to my android application.
I solved this problem successfully by using the solution given in Passing data from java class to Web View html.
The problem that I'm facing is when I'm trying to call MainActivity methods from JavaScriptInterface.java, the methods are not being called or no errors are given.
here's what I have tried so far:
MainActivity act=new MainActivity();
act.myMethod() //This method is available in my activity
but it is not being called.
and
((MainActivity)getActivity).myMethod();
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTheme(R.style.AppTheme);
setContentView(R.layout.activity_main);
}
public void myMethod() {
Toast.makeText(this, "Inside MainActivity", Toast.LENGTH_SHORT).show();
}
}
//JavaScriptInterface class
class JavaScriptInterface {
Context mContext;
JavaScriptInterface(Context c) {
mContext = c;
}
/** Show a toast from the web page */
#JavascriptInterface
public void onButtonClick(String toast1, String toast2) {
Toast.makeText(mContext, toast1+" | "+toast2, Toast.LENGTH_SHORT).show(); //THIS IS WORKING
MainActivity act=new MainActivity();
act.myMethod(); //NOT WORKING
}
}
Technically, the myMethod will get called, but since you create the MainActivity yourself, it's not attached to anything.
In general, you shouldn't create a new MainActivity instance this way. To open a new MainActivity, you use an Intent.
In your case, you should have a reference to the original MainActivity instance, and call this method there. Not create a new one in any way, as you already have it running.
An easy way to solve it:
MainActivity.this.myMethod("Hello there")
You don't have to store mContext . You already are inside of MainActivity.
So, the full code would be:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView myWebView = findViewById(R.id.webview);
myWebView.loadUrl("http://www.google.com");
myWebView.addJavascriptInterface(new WebAppInterface(), "Android");
}
public void myMethod(String test){
Toast.makeText(this, test, Toast.LENGTH_SHORT).show();
}
public class WebAppInterface {
/** Show a toast from the web page */
#JavascriptInterface
public void showToast(String toast) {
MainActivity.this.myMethod("Hello there");
}
}
}
In fact, I think you can even avoid having the MainActivity.this. , and call myMethod directly.
You are creating another object of MainActivity this is why its not getting displayed. You are passing the activity context to the interface so you can just
((MainActivity)mContext).myMethod();
Sample MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
WebView myWebView = findViewById(R.id.webview);
myWebView.loadUrl("http://www.google.com");
myWebView.addJavascriptInterface(new WebAppInterface(this), "Android");
}
public void myMethod(String test){
Toast.makeText(this, test, Toast.LENGTH_SHORT).show();
}
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 showToast(String toast) {
((MainActivity)mContext).myMethod("hello");
}
}
}
Check out android documentation for more info

How to enable javascript webview for API 15

I want to make webview which load javascript, but not working in API 15. I already test on API 21 and working. Anyone know to make it working? Thanks
public class MainActivity extends AppCompatActivity {
private WebView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (WebView) this.findViewById(R.id.webView);
view.getSettings().setJavaScriptEnabled(true);
view.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
view.setWebViewClient(new MyBrowser());
view.loadUrl("http://mywebsite.com");
}
private class MyBrowser extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && view.canGoBack()) {
view.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
Method shouldOverrideUrlLoading(WebView view, String url) must return true, only if you want to load url different from original, or not to load at all. In this case can return false and load url in usual way. If your page executes JS by loading 'javascript:' link, you can return false for all urls, started with javascript:. Note, that on SDK 24+, shouldOverrideUrlLoading(WebView view, WebResourceRequest request) called instead.

Android webview not rendering CSS and angular

I am trying to load a URL in to android native webview, but it does not render CSS and Angular
CODE:
WebView wvFAQs = (WebView) mFragmentView.findViewById(R.id.wvUrls);
Map<String, String> headersMap = new HashMap<>();
headersMap.put(ApiConstants.AUTHORIZATION, BuildConfig.SS_API_AUTH);
wvFAQs.setWebViewClient(new WebViewClient() {
#SuppressWarnings("deprecation")
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}
#TargetApi(Build.VERSION_CODES.N)
#Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return false;
}
});
wvFAQs.getSettings().setJavaScriptEnabled(true);
wvFAQs.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
wvFAQs.loadUrl(mUrl,headersMap);
ERRORS:
"Uncaught ReferenceError: _ is not defined",
"Uncaught ReferenceError: angular is not defined",
"Uncaught ReferenceError: $ is not defined",
but this URL works fine in mobile browsers (chrome & default android browser).
when i googled this issue, i came to know that i need to enable html5 support feature in webiew, here is the link, but still not working.
Can anyone tell me what might be the issue? is there any issue with the URL or webview?
I use this Java code to load the webview:
public class MainActivity extends AppCompatActivity {
private WebView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
view = (WebView) this.findViewById(R.id.webView);
view.getSettings().setJavaScriptEnabled(true);
view.setWebViewClient(new MyBrowser());
view.loadUrl("file:///android_asset/www/index.html"); //try js alert
view.setWebChromeClient(new WebChromeClient()); // adding js alert support
}
private class MyBrowser extends WebViewClient {
#Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && view.canGoBack()) {
view.goBack(); //method goback()
return true;
}
return super.onKeyDown(keyCode, event);
}
What I can say is if that you use Jquery you need to add it to your assets because external links like from cdn like:
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
would not load.

WebViewClient onPageFinished never called

I've looked at several similar posts on S/O but I can't find an answer to my problem. I'm trying to grab the html from a web view but I can't get my "onPageFinished() callback to fire. I've even tried using the progress callback on the WebChromeClient but nothing is working. neigh the web client or web chrome client receive any callbacks. I am running this code as an Android unit test and using a test HTML from the assets directory which I've confirmed via assert and debug is being located. What am I missing?
** Update **
I've stepped through the test method in debug. It does load the html (it's a unit test so I cannot actually see the rendered content). It then blocks on the wait() call, times out then performs the assert at the bottom without ever receiving a callback from either client. (Both the web client and chrome client should/would call notify())
The difference here would be that I am running within an Android unit test. The WebView is NOT attached to any Activity or container. I'm wondering if that has anything to do with the missing callbacks. I'll try sticking it on an Activity to see if it makes any difference.
** /Update **
public class MyWebViewTest extends InstrumentationTestCase {
private WebView webView;
private String html;
public void setUp() throws Exception {
super.setUp();
Context context = getInstrumentation().getContext();
this.webView = new WebView(context);
assertTrue("requires test.html",
Arrays.asList(context.getResources().getAssets().list("www")).contains("test.html"));
}
public void tearDown() throws Exception {
}
#JavascriptInterface
public void viewContent(String content) {
this.html = content;
}
public void testCanLoadAndReadWebContentFromWebView() throws Exception {
webView.addJavascriptInterface(this, "_webContainer");
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView webView, String url) {
super.onPageFinished(webView, url);
onPageLoaded(webView);
}
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
}
});
webView.setWebChromeClient(new WebChromeClient() {
#Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if(newProgress==100)
onPageLoaded(webView);
}
});
webView.loadUrl("file:///android_asset/www/test.html");
synchronized (this) {
wait(5000);
}
assertNotNull(html);
}
private void onPageLoaded(WebView webView) {
webView.loadUrl("javascript:window._webContainer.viewContent(document.documentElement.innerHTML);");
synchronized (this) {
notify();
}
}
}
I was correct in my assumption! When the WebView is not attached to an Activity it will not load, render, or do much of anything. I ended up extending ActivityInstrumentationTestCase2 and attaching the web view to an Activity. At that point my breakpoints in the callbacks started lighting up. Here's my working test case:
public class MyWebViewTest extends ActivityInstrumentationTestCase2<TestMeActivity> {
private WebView webView;
private String html;
public MyWebViewTest() {
super(TestMeActivity.class);
}
public void setUp() throws Exception {
super.setUp();
Context context = getInstrumentation().getContext();
this.webView = getActivity().getView();
assertTrue("requires test.html",
Arrays.asList(context.getResources().getAssets().list("www")).contains("test.html"));
}
public void tearDown() throws Exception {
}
#JavascriptInterface
public void viewContent(String content) {
this.html = content;
}
public void testCanLoadAndReadWebContentFromWebView() throws Exception {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
configureWebView();
}
});
synchronized (MyWebViewTest.this) {
MyWebViewTest.this.wait(25000);
}
assertEquals("<head></head><body>\n" +
"Hello\n" +
"\n" +
"</body>",html);
}
private void configureWebView() {
webView.addJavascriptInterface(this, "_webContainer");
WebSettings webSettings = webView.getSettings();
webSettings.setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView webView, String url) {
super.onPageFinished(webView, url);
onPageLoaded(webView);
}
});
webView.loadUrl("file:///android_asset/www/test.html");
}
#TargetApi(Build.VERSION_CODES.KITKAT)
private void onPageLoaded(WebView webView) {
webView.evaluateJavascript("javascript:window._webContainer.viewContent(document.documentElement.innerHTML);",
new ValueCallback<String>() {
#Override
public void onReceiveValue(String value) {
synchronized (MyWebViewTest.this) {
MyWebViewTest.this.notify();
}
}
}
);
}
}
and here's the Activity I threw together to back it:
public class TestMeActivity extends Activity{
private WebView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
view = new WebView(this);
setContentView(view);
}
public WebView getView() {
return view;
}
}
In short there is quite a bit of work involved in testing the contents of a WebView from an Android TestCase. You have to add a Javascript interface to the web view, insert some Javascript to invoke the internal Javascript interface object, passing the contents of the web view, through the interface and finally collect it in your test case. I sure wish it were easier but this is the best I can come up with.

Binding JavaScript code to Android code

Im trying to invoke a method in java from javascript, but this doesn't happen when I run the application in the emulator, the application stops when it is suppose to call the method in java. here is the java code:
import android.os.Bundle;
import android.webkit.WebView;
import com.phonegap.*;
public class App extends DroidGap {
WebView webView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = new WebView(this);
webView.addJavascriptInterface(new message(), "Show");
super.loadUrl("file:///android_asset/www/index.html");
}
class message {
String msg() {
return "Hello World!!";
}
}
}
here is the javascript:
<script type="text/javascript">
{
alert("Start");
alert(Show.msg());
alert("End");
}
</script>
It shows the first alert but nothing thereafter, can anyone help?
Your problem is that you're half using PhoneGap and half not. You're creating a separate WebView class from PhoneGap's. The WebView class that you added "Show" to never gets used. Instead the WebView class that is a member of the super (DroidGap) is.
You should do one of two things.
Use PhoneGap's plugin structure (see examples here)
Don't use PhoneGap at all and have a class that looks more like the following:
public class act extends Activity {
WebView webView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
webView = new WebView(this);
webView.getSettings().setJavaScriptEnabled(true);
// Set JS alert() hook
webView.setWebChromeClient(new WebChromeClient() {
public boolean onJsAlert(WebView view, String url, String message, JsResult result)
{
return false;
}
});
webView.loadUrl("file:///android_asset/www/index.html");
// Add JS libraries
webView.addJavascriptInterface(new message(), "Show");
}
class message {
public String msg() {
return "Hello World!!";
}
}
}
Note that the method msg needs to be public
Why not just use AlertDialog?
private void showDialog(int title, String message) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton(R.string.ok_button, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
}
});
builder.show();
}

Categories

Resources