There are 2 different ways to get html content from android webview.
1) Using Javascript
In this approach, url will be loaded by webview itself. Means each and every url will be invoked in the webview context. so webview will manage cookies and http session automatically.
2) Using Java only to get html content from webview.
In this approach, webview will not be responsible for fetching the content from remote servers. We have to handle invocation of urls and have to fetch html content using code and then we can perform whatever operations we require on content before setting it in the webview.
So maintaining cookies and http session will be our responsibility.
In the example snippet below for this approach will show a workaround for maintaining http session.
1) Using Javascript
First you have to configure javascript interface for webview, using below method
Here 1st parameter is the MyJavaScriptInterface class, that you have to write as below.
and 2nd parameter is the name of the javascript object you will use to call the method you write (showHTML).
Note that annotation ‘ @JavascriptInterface’ on the showHTML method. it is mandatory to work this propertly for android >=4.2.
Another thing to keep in mind is that, from showHTML method, you will not able to access other components of your activity directly. You have to post runnable objects to a handler. and write all the logic to access activity’s components inside the run method of runnable.
Now everyting is setup. You just have to call showHTML method explicitly when the page loading is finished into the webview.
For this you have to implement WebviewClient which will be notified by android once page is loaded into the webview, and from that you can invoke showHTML method using javascript and pass the html content loaded into webview.
This can be achieved using below code.
Below is the complete activity code you can refer to if anything is missed in above code snippet.
If you are using proguard while exporting your apps then following properties must be included in proguard-project.txt (proguard config file) .
2) Using Java only to get html content from webview.
In this approach, you have to handle page loading events (page loading started, page loading finished) of webview based on your requirements and from there you have to use httpclient api to actually hit the url and get the content.
this way you will have the access to the html content returned by remote server and you can modify the content as per your needs before/after it is rendered into the webview.
Below is the complete code for this.
As stated above, this approach will not maintain cookies and http sessions.
So if you don't have requirement to maintain http session, then above code snippet is sufficient. Otherwise you have to implement additional code to achieve session management.
This is how you can achieve it.
First thing is you have to make your httpclient instance global. Means, you have to use same http client for executing each and every request.
Also you have to create global HttpContext and CookieStore objects, which will be used for executing http requests.
You can use below method to initialize the httpclient.
Now you have to execute each and every request in localContext, which is using cookieStore internally.
And after invoking the request urls, you have to call below method to sync the cookies with webview.
Thats it! Feel free to add your feedback/comments if there are any.
1) Using Javascript
In this approach, url will be loaded by webview itself. Means each and every url will be invoked in the webview context. so webview will manage cookies and http session automatically.
2) Using Java only to get html content from webview.
In this approach, webview will not be responsible for fetching the content from remote servers. We have to handle invocation of urls and have to fetch html content using code and then we can perform whatever operations we require on content before setting it in the webview.
So maintaining cookies and http session will be our responsibility.
In the example snippet below for this approach will show a workaround for maintaining http session.
1) Using Javascript
First you have to configure javascript interface for webview, using below method
webview.addJavascriptInterface(new MyJavaScriptInterface(this), "HtmlViewer");
Here 1st parameter is the MyJavaScriptInterface class, that you have to write as below.
and 2nd parameter is the name of the javascript object you will use to call the method you write (showHTML).
class MyJavaScriptInterface { private Context ctx; MyJavaScriptInterface(Context ctx) { this.ctx = ctx; } @JavascriptInterface public void showHTML(String html) { //code to use html content here handlerForJavascriptInterface.post(new Runnable() { @Override public void run() { Toast toast = Toast.makeText(this, "Page has been loaded in webview. html content :"+html_, Toast.LENGTH_LONG); toast.show(); }}); } }
Note that annotation ‘ @JavascriptInterface’ on the showHTML method. it is mandatory to work this propertly for android >=4.2.
Another thing to keep in mind is that, from showHTML method, you will not able to access other components of your activity directly. You have to post runnable objects to a handler. and write all the logic to access activity’s components inside the run method of runnable.
Now everyting is setup. You just have to call showHTML method explicitly when the page loading is finished into the webview.
For this you have to implement WebviewClient which will be notified by android once page is loaded into the webview, and from that you can invoke showHTML method using javascript and pass the html content loaded into webview.
This can be achieved using below code.
webview.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { webview.loadUrl("javascript:window.HtmlViewer.showHTML" + "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');"); } });
Below is the complete activity code you can refer to if anything is missed in above code snippet.
public class TestActivity extends Activity { Handler handlerForJavascriptInterface = new Handler(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.webview); final WebView webview = (WebView) findViewById(R.id.browser); webview.getSettings().setJavaScriptEnabled(true); webview.addJavascriptInterface(new MyJavaScriptInterface(this), "HtmlViewer"); webview.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { webview.loadUrl("javascript:window.HtmlViewer.showHTML" + "('<html>'+document.getElementsByTagName('html')[0].innerHTML+'</html>');"); } } ); webview.loadUrl("http://android-in-action.com/index.php?post/" + "Common-errors-and-bugs-and-how-to-solve-avoid-them"); } class MyJavaScriptInterface { private Context ctx; MyJavaScriptInterface(Context ctx) { this.ctx = ctx; } public void showHTML(String html) { final html_ = html; handlerForJavascriptInterface.post(new Runnable() { @Override public void run() { Toast toast = Toast.makeText(this, "Page has been loaded in webview. html content :"+html_, Toast.LENGTH_LONG); toast.show(); } } ); } } }
If you are using proguard while exporting your apps then following properties must be included in proguard-project.txt (proguard config file) .
-keepattributes JavascriptInterface -keep public class com.mypackage.MyClass$MyJavaScriptInterface -keep public class * implements com.mypackage.MyClass$MyJavaScriptInterface -keepclassmembers class com.mypackage.MyClass$MyJavaScriptInterface { <methods>; }
In this approach, you have to handle page loading events (page loading started, page loading finished) of webview based on your requirements and from there you have to use httpclient api to actually hit the url and get the content.
this way you will have the access to the html content returned by remote server and you can modify the content as per your needs before/after it is rendered into the webview.
Below is the complete code for this.
import java.io.IOException; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.util.EntityUtils; import android.app.Activity; import android.graphics.Bitmap; import android.os.Bundle; import android.webkit.WebView; import android.webkit.WebViewClient; /** * getting html content from webview using java only. not using javascript for * that. */ public class WebviewTestActivity1 extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_webview_test_activity1); final WebView webview = (WebView) findViewById(R.id.webview1); webview.getSettings().setJavaScriptEnabled(true); WebViewClient webViewClient = new WebViewClient() { /** * this method will be invoked when page started loading into the * webview. so you can use thid method if you want to modifiy the * content before it is rendered. */ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); String htmlContent = getRemoteContent(url); webview.loadDataWithBaseURL(url, htmlContent, null, "utf-8", url); } /** * this method will be invoked when page loading is finished into * the webview. */ @Override public void onPageFinished(WebView view, String url) { // TODO Auto-generated method stub super.onPageFinished(view, url);
// similar code as above method will go here . } }; webview.setWebViewClient(webViewClient); } /** * this method will hit the remote url and get the content. this content * will be set in the webview. */ private String getRemoteContent(String url) { HttpGet pageGet = new HttpGet(url); HttpClient client = new DefaultHttpClient(); ResponseHandler<String> handler = new ResponseHandler<String>() { public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException { HttpEntity entity = response.getEntity(); String html; if (entity != null) { html = EntityUtils.toString(entity); return html; } else { return null; } } }; String pageHTML = null; try { pageHTML = client.execute(pageGet, handler); //if you want to manage http sessions then you have to add localContext as a third argument to this method and have uncomment below line to sync cookies. //syncCookies(); } catch (Exception e) { e.printStackTrace(); } // you can filter your html content here if you wish before displaying // in webview return pageHTML; } }
As stated above, this approach will not maintain cookies and http sessions.
So if you don't have requirement to maintain http session, then above code snippet is sufficient. Otherwise you have to implement additional code to achieve session management.
This is how you can achieve it.
First thing is you have to make your httpclient instance global. Means, you have to use same http client for executing each and every request.
Also you have to create global HttpContext and CookieStore objects, which will be used for executing http requests.
You can use below method to initialize the httpclient.
private static DefaultHttpClient httpClient = null; private static void initHttpClient() { httpClient = new DefaultHttpClient(); ClientConnectionManager cm = httpClient.getConnectionManager(); SchemeRegistry sr = cm.getSchemeRegistry(); sr.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); sr.register(new Scheme("https", TrustAllSSLSocketFactory.getSocketFactory(), 443)); cookieStore = new BasicCookieStore(); localContext = new BasicHttpContext(); localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); }
Now you have to execute each and every request in localContext, which is using cookieStore internally.
And after invoking the request urls, you have to call below method to sync the cookies with webview.
private void syncCookies() { Cookie sessionInfo; List<Cookie> cookies = client.getCookieStore().getCookies(); Log.d(TAG, "cookies = " + cookies); if (!cookies.isEmpty()) { WebView webView = (WebView) findViewById(R.id.webView1); CookieSyncManager.createInstance(webView.getContext()); CookieManager cookieManager = CookieManager.getInstance(); for (Cookie cookie : cookies) { sessionInfo = cookie; String cookieString = sessionInfo.getName() + "=" + sessionInfo.getValue() + "; domain=" + sessionInfo.getDomain(); Log.d(TAG, "cookieString = " + cookieString); cookieManager.setCookie("<your_host_address_here>", cookieString); CookieSyncManager.getInstance().sync(); } } }
Thats it! Feel free to add your feedback/comments if there are any.
Very nice blog,keep sharing more posts with us.
ReplyDeleteandroid app develoment course
I'm no expert, but I believe you just made an excellent point. You certainly fully understand what youre speaking about, and
ReplyDeleteI can truly get behind that. content://com.android.browser.home/index
Positive site, where did u come up with the information on this posting?I have read a few of the articles on your website now, and I really like your style.
ReplyDeleteThanks a million and please keep up the effective work.https://1asiaqq.net/