Hello everybody,
I'm writing this post to help fellow Android Developers to overcome the barrier of not being able to play HTML 5 Videos inside the Android webview.
Many a times, you want to build a App that integrates a Webpage which essentially has a <video /> tag that plays a particular Video.
Now this Webpage works fine on all desktop browsers. It works fine when its online. But when you integrate it in a Android App, it just wont play the Video in the app webview browser.
One major problem for this to happen is due to Video Encoding, I'd suggest that you encode your Video according to the Standards mentioned on the following link
http://developer.android.com/guide/appendix/media-formats.html
Even after doing this the video is not playing, is because, the default Web Browser of Android wont support the auto play attribute of the <video /> tag of html5.
I will walk you through the Procedure that I followed to get this working.
I placed the HTML page and the Video File in the Assets Folder of my Android Project
Here is a sample of my HTML page, before modifying it to meet my needs.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<title>screen2</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="css/main-v1.css" rel="stylesheet" type="text/css">
<link href="css/screen2-v1.css" rel="stylesheet" type="text/css">
<script src="js/jQueryTest.js"></script>
</head>
<body>
<video id="video1" src="video/mov_bbb.mp4"></video>
</body>
</html>
I'm writing this post to help fellow Android Developers to overcome the barrier of not being able to play HTML 5 Videos inside the Android webview.
Many a times, you want to build a App that integrates a Webpage which essentially has a <video /> tag that plays a particular Video.
Now this Webpage works fine on all desktop browsers. It works fine when its online. But when you integrate it in a Android App, it just wont play the Video in the app webview browser.
One major problem for this to happen is due to Video Encoding, I'd suggest that you encode your Video according to the Standards mentioned on the following link
http://developer.android.com/guide/appendix/media-formats.html
Even after doing this the video is not playing, is because, the default Web Browser of Android wont support the auto play attribute of the <video /> tag of html5.
I will walk you through the Procedure that I followed to get this working.
I placed the HTML page and the Video File in the Assets Folder of my Android Project
Here is a sample of my HTML page, before modifying it to meet my needs.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<title>screen2</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="css/main-v1.css" rel="stylesheet" type="text/css">
<link href="css/screen2-v1.css" rel="stylesheet" type="text/css">
<script src="js/jQueryTest.js"></script>
</head>
<body>
<video id="video1" src="video/mov_bbb.mp4"></video>
</body>
</html>
Now, what I did was to store my media file (mov_bbb.mp4) in "mnt/sdcard/" of the Android Device.
I did this by Asynchronously transferring the file from the Assets folder to the "mnt/sdcard" folder. This is done only when the App is first installed and run for the first time.
Following is the code in MainActivity.java
package com.example.dms;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebSettings.PluginState;
import android.webkit.WebSettings.RenderPriority;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class MainActivity extends Activity{
private static final String TAG = "Copying File or Folder";
//Shared Preference
private String appName = "com.example.dsm";
private SharedPreferences pref;
private Editor editor;
//WebView Variables
private JsHandler _jsHandler;
private WebView myWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myWebView = (WebView) findViewById(R.id.webView);
myWebView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent event) {
// TODO Auto-generated method stub
if(event.getAction() == MotionEvent.ACTION_DOWN && !view.hasFocus()) {
view.requestFocus();
}
return false;
}
});
pref = getApplicationContext().getSharedPreferences(appName, MODE_PRIVATE);
Boolean b = (pref.getBoolean(appName, false));
Log.d("BgCopy","Boolean Data is "+b);
if(b == false)
{
MyTask task = new MyTask();
task.execute("resources");
}
else if(b == true)
{
Log.d("BgCopy", "Folder Already Exists, do Not Copy");
initWebView();
}
}
private void initWebView(){
//Tell the WebView to enable javascript execution.
myWebView.getSettings().setJavaScriptEnabled(true);
myWebView.setBackgroundColor(Color.parseColor("#808080"));
//Set whether the DOM storage API is enabled.
myWebView.getSettings().setDomStorageEnabled(true);
//setBuiltInZoomControls = false, removes +/- controls on screen
myWebView.getSettings().setBuiltInZoomControls(false);
myWebView.getSettings().setPluginState(PluginState.ON);
myWebView.getSettings().setAllowFileAccess(true);
myWebView.getSettings().setAppCacheMaxSize(1024 * 8);
myWebView.getSettings().setAppCacheEnabled(true);
_jsHandler = new JsHandler(this, myWebView);
myWebView.addJavascriptInterface(_jsHandler, "JsHandler");
myWebView.getSettings().setUseWideViewPort(false);
myWebView.setWebChromeClient(new WebChromeClient());
myWebView.setWebViewClient(new WebViewClient());
// these settings speed up page load into the webview
myWebView.getSettings().setRenderPriority(RenderPriority.HIGH);
myWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
myWebView.requestFocus(View.FOCUS_DOWN);
// load the main.html file that kept in assets folder
myWebView.loadUrl("file:///android_asset/screen2.html");
}
private void copyAssets(String path)
{
String[] files = null;
try
{
files = getAssets().list(path);
for(String fileName:files)
{
Log.d("BgCopy", "file / folder name "+fileName);
}
} catch (IOException e)
{
e.printStackTrace();
}
if (files.length == 0)
{
copyFile(path);
}
else
{
File dir = new File(getExternalFilesDir(null), path);
if (!dir.exists())
{
dir.mkdir();
}
for (int i = 0; i < files.length; i++)
{
copyAssets(path + "/" + files[i]);
}
}
doneCopy();
}
private void copyFile(String filename)
{
InputStream in = null;
File file;
OutputStream out = null;
try
{
in = getAssets().open(filename);
} catch (IOException e)
{
e.printStackTrace();
}
file = new File(getExternalFilesDir(null), filename);
try
{
out = new FileOutputStream(file);
} catch (FileNotFoundException e)
{
Log.e(TAG, "ERROR WITH out = new FileOutputStream(file);");
e.printStackTrace();
}
byte[] data;
try
{
data = new byte[in.available()];
in.read(data);
out.write(data);
in.close();
out.close();
} catch (IOException e1)
{
e1.printStackTrace();
}
}
private void doneCopy()
{
Log.d("BgCopy", "Done Copying Files");
}
public class MyTask extends AsyncTask<String,Long,Boolean>
{
ProgressDialog progress;
protected void onPreExecute()
{
progress = ProgressDialog.show(MainActivity.this,"","Loading...",true);
}
protected void onPostExecute(Boolean success)
{
progress.dismiss();
editor = pref.edit();
editor.putBoolean(appName, true);
editor.commit();
initWebView();
}
protected void onProgressUpdate(Long... values)
{
progress.setMessage("Transferred " + values[0] + " bytes");
}
@Override
protected Boolean doInBackground(String... files) {
// TODO Auto-generated method stub
copyMe(files[0]);
return true;
}
private void copyMe(String s)
{
copyAssets(s);
}
}
}
Now I created a Class that will act as an Interface between Java and Javascript of the Loaded HTML page.
I named it JsHandler.java
package com.example.dms;
import java.io.IOException;
import com.example.dms.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.webkit.JavascriptInterface;
import android.webkit.WebView;
public class JsHandler {
Activity activity;
String TAG = "JsHandler";
WebView webView;
public JsHandler(Activity _contxt,WebView _webView) {
activity = _contxt;
webView = _webView;
}
/**
* This function handles call from JS
*/
@JavascriptInterface
public void initVideo()
{
webView.loadUrl("javascript:playVideo()");
}
public void initAudio()
{
webView.loadUrl("javascript:playAudio()");
}
/**
* This function handles call from Android-Java
*/
public void javaFnCall(String jsString) {
final String webUrl = "javascript:diplayJavaMsg('"+jsString+"')";
// Add this to avoid android.view.windowmanager$badtokenexception unable to add window
if(!activity.isFinishing())
// loadurl on UI main thread
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
webView.loadUrl(webUrl);
}
});
}
/**
* function shows Android-Native Alert Dialog
*/
public void showDialog(String msg){
AlertDialog alertDialog = new AlertDialog.Builder(activity).create();
alertDialog.setTitle(activity.getString(R.string.app_dialog_title));
alertDialog.setMessage(msg);
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE,activity.getString(R.string.ok_text), new DialogInterface.OnClickListener()
{
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
});
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE,activity.getString(R.string.cancel_text), new DialogInterface.OnClickListener()
{
@Override
public void onClick(DialogInterface dialog, int which)
{
dialog.dismiss();
}
});
alertDialog.show();
}
}
Now I modified the HTML page to reflect the path of the Video that resides in "mnt/sdcard"
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<html>
<head>
<title>screen2</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link href="css/main-v1.css" rel="stylesheet" type="text/css">
<link href="css/screen2-v1.css" rel="stylesheet" type="text/css">
<script src="js/jQueryTest.js"></script>
<script>
function playVideo()
{
var cV = document.getElementById("video1");
cV.addEventListener('ended', function ()
{
cV.removeEventListener('ended');
playAudio();
}, false);
cV.play();
}
function playAudio()
{
var cA = document.getElementById("audio1");
cA.addEventListener('ended', function ()
{
cA.removeEventListener('ended');
playVideo();
}, false);
cA.play();
}
function init(){
JsHandler.initVideo();
}
</script>
<script>
$(document).ready(function(){
init();
});
</script>
</head>
<body>
<audio id="audio1" src="/mnt/sdcard/Android/data/com.exapmle.dms/files/resources/audio/screen2_a.mp3"></audio>
<video id="video1" src="/mnt/sdcard/Android/data/com.exapmle.dms/files/resources/video/mov_bbb.mp4"></video>
</body>
</html>
As you can see, I've added a couple of Javascript methods in the code.
The HTML page will execute the code in init(); method when its completely loaded, gives a call to JsHandler.initVideo(); method which resides in JsHandler.java file.
This function in turn calls the playVideo(); method written in the HTML page.
This is how you will be able to play HTML 5 Videos inside android webview.
You maybe wondering, why not call playVideo(); method directly in the init(); method. Well, I've tried it and it didn't work(At least for me).
I hope it help's anyone wanting such functionality.
Bye!!
can you please give us xml code
ReplyDeleteMicro Titanium By Babyliss Pro (Babyliss Pro) - TITanium
ReplyDeleteMicro Titanium By Babyliss Pro. 1.20. - Add more details. Product ID. Babyliss Pro. mens titanium braclets Product Number. nano titanium by babyliss pro 1.20. Product titanium tv apk Details. micro touch titanium trimmer Add more titanium crystal details.