作为一个WEB开发者,HTML5让我兴奋,因为它可以将桌面应用程序功能带入浏览器中。但在国内,看着到处横行的IE8版本以下的浏览器,觉得到能大规模使用HTML5技术的那天,还遥遥无期。但面对iOS及Android等平台的手机用户越来越多,基于Webkit内核的移动浏览器一定能让HTML5先大规模应用起来。这将对对移动 Web 应用程序开发具有重大影响。
作为非常看好未来手机网络的我,也在一直研究Android平台的应用的开发,也许是因为自己更熟悉HTML及CSS、JS,并受到之前使用HTML和VC开发程序的影响,我也更愿意使用HTML来做Android程序的UI….
09年,在开发《华夏风云》游戏的时候,使用了基于Google Gear插件来做了很多离线应用,可惜Gear已经不在更新开发,被HTML5取代。下面介绍基于HTML 5 的Web 应用程序的本地存储,不再废话,例子说明一切。
一、离线应用缓存 HTML 5 Offline Application Cache
- 在服务器上添加MIME TYPE支:text/cache-manifest
如果在Apache下添加:
1 |
AddType text/cache-manifest manifest |
如果为Nginx,在添加:
1 |
text/cache-manifest manifest; |
或者通过动态程序生成:
1 |
header( 'Content-type: text/cache-manifest; charset=UTF-8' ); |
新建清单文件 manifest
03 |
# Cache manifest version 0.0.1 |
04 |
# If you change the version number in this comment, |
05 |
# the cache manifest is no longer byte-for-byte |
08 |
/app/static/default/js/models/prototype.js |
09 |
/app/static/default/js/controllers/init.js |
12 |
# All URLs that start with the following lines |
18 |
# Additional items to cache. |
19 |
/app/static/default/images/main/ bg .png |
- 给 <html> 标签加 manifest 属性:
建立manifest文件之后,需要在HTML文档中声明:
声明清单文件 manifest
<!doctype html> <html manifest="notebook.manifest"> <head> <meta charset="UTF-8" /> <meta name = "viewport" content = "width = device-width, user-scalable = no"> <title>NoteBook</title> </head> <body> </body> </html>
二、Key-Value Storage
三、Using the JavaScript Database
四、Android下使用WebView来做基于HTML5的App
见如下AndroidManifest.xml
01 |
< ? xml version = "1.0" encoding = "utf-8" ?> |
02 |
< manifest android:versionName = "1.0" android:versionCode = "1" package = "com.xinze.joke" xmlns:android = "http://schemas.android.com/apk/res/android" > |
03 |
< application android:label = "@string/app_name" android:icon = "@drawable/icon" > |
04 |
< activity android:label = "@string/app_name" android:theme = "@android:style/Theme.NoTitleBar" android:configChanges = "orientation|keyboardHidden|navigation" android:name = ".Joke" > |
06 |
< action android:name = "android.intent.action.MAIN" > |
07 |
< category android:name = "android.intent.category.LAUNCHER" > |
08 |
</ category ></ action ></ intent > |
11 |
< uses android:name = "android.permission.INTERNET" -permission = "" > |
注意:
1 |
< uses android:name = "android.permission.INTERNET" -permission = "" ></ uses > |
, 允许网络应用,必须!!
Android主程序代码:
001 |
package com.xinze.joke; |
003 |
import android.app.Activity; |
004 |
import android.app.AlertDialog; |
005 |
import android.app.AlertDialog.Builder; |
007 |
import android.content.DialogInterface; |
009 |
import android.os.Bundle; |
010 |
import android.view.KeyEvent; |
011 |
import android.view.View; |
012 |
import android.view.Window; |
013 |
import android.view.WindowManager; |
014 |
import android.webkit.JsPromptResult; |
015 |
import android.webkit.JsResult; |
016 |
import android.webkit.WebChromeClient; |
017 |
import android.webkit.WebView; |
018 |
import android.webkit.WebViewClient; |
020 |
import android.webkit.WebStorage ; |
022 |
public class Joke extends Activity { |
024 |
/** Called when the activity is first created. */ |
026 |
public void onCreate(Bundle savedInstanceState) { |
027 |
super .onCreate(savedInstanceState); |
029 |
final WebView wv = new WebView( this ); |
031 |
// 覆盖默认后退按钮的作用,替换成WebView里的查看历史页面 |
032 |
wv.setOnKeyListener( new View.OnKeyListener() { |
035 |
public boolean onKey(View v, int keyCode, KeyEvent event) { |
036 |
if (event.getAction() == KeyEvent.ACTION_DOWN) { |
037 |
if ((keyCode == KeyEvent.KEYCODE_BACK) && wv.canGoBack()) { |
047 |
wv.getSettings().setJavaScriptEnabled( true ); |
049 |
wv.getSettings().setJavaScriptCanOpenWindowsAutomatically( true ); |
050 |
wv.getSettings().setDatabaseEnabled( true ); |
051 |
wv.getSettings().setDatabasePath( "/data/data/com.xinze.joke/databases" ); |
054 |
WebViewClient wvc = new WebViewClient() { |
057 |
public boolean shouldOverrideUrlLoading(WebView view, String url) { |
059 |
// 记得消耗掉这个事件。给不知道的朋友再解释一下,Android中返回True的意思就是到此为止吧,事件就会不会冒泡传递了,我们称之为消耗掉 |
065 |
wv.setWebViewClient(wvc); |
067 |
// 创建WebViewChromeClient |
068 |
WebChromeClient wvcc = new WebChromeClient() { |
072 |
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) { |
073 |
// 构建一个Builder来显示网页中的alert对话框 |
074 |
Builder builder = new Builder(Joke. this ); |
075 |
builder.setTitle( "笑死不偿命" ); |
076 |
builder.setMessage(message); |
077 |
builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() { |
079 |
public void onClick(DialogInterface dialog, int which) { |
083 |
builder.setCancelable( false ); |
091 |
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) { |
092 |
Builder builder = new Builder(Joke. this ); |
093 |
builder.setTitle( "删除确认" ); |
094 |
builder.setMessage(message); |
095 |
builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() { |
098 |
public void onClick(DialogInterface dialog, int which) { |
103 |
builder.setNeutralButton(android.R.string.cancel, new AlertDialog.OnClickListener() { |
106 |
public void onClick(DialogInterface dialog, int which) { |
111 |
builder.setCancelable( false ); |
119 |
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, |
120 |
JsPromptResult result) { |
122 |
return super .onJsPrompt(view, url, message, defaultValue, result); |
126 |
public void onExceededDatabaseQuota(String url, String |
127 |
databaseIdentifier, long currentQuota, long estimatedSize, long |
128 |
totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) { |
129 |
quotaUpdater.updateQuota( 204801 ); |
134 |
wv.loadUrl( "http://192.168.1.14/index.html" ); |
136 |
// 设置setWebChromeClient对象 |
137 |
wv.setWebChromeClient(wvcc); |
使用 JavaScript Database 的时候,需要特别注意:setDatabaseEnabled 以及 onExceededDatabaseQuota!
在Android上做HTML5应用用到了Webkit这个浏览器内核,这里具体不讨论Webkit for Android。
HTML5如何在安卓上开发HTML5应用
Android开发HTML5应用实际项目面临的问题1:
Android的HTML5应用程序概述 如何适配多分辨率的Android设备?
如何在Android中构建HTML5应用程序?
如何在Android中调试HTML5应用程序?
如何在Android中使用HTML5的本地储存?
如何在Android中使用HTML5的本地数据库?
如何在Android中使用HTML5的地理定位?
如何在Android中构建HTML5离线应用?
如何使用Canvas进行绘图?
上述问题这里提供一个ppt和参考代码
- package com.example.androidwebview;
-
- import android.os.Bundle;
- import android.annotation.SuppressLint;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Bitmap;
-
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.ViewGroup;
- import android.view.Window;
- import android.view.WindowManager;
-
- import android.webkit.GeolocationPermissions;
- import android.webkit.WebChromeClient;
- import android.webkit.WebSettings;
- import android.webkit.WebStorage;
- import android.webkit.WebView;
- import android.webkit.WebSettings.RenderPriority;
- import android.webkit.WebViewClient;
-
- public class MainActivity extends Activity {
-
- private WebView mWebView;
-
- private WebViewClient mWebViewClient = new WebViewClient() {
-
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- mWebView.loadUrl(url);
-
-
- return true;
- }
-
- @Override
- public void onPageFinished(WebView view, String url) {
- super.onPageFinished(view, url);
- }
-
- @Override
- public void onPageStarted(WebView view, String url, Bitmap favicon) {
- super.onPageStarted(view, url, favicon);
- }
- };
-
-
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
- mWebView.goBack();
- return true;
- }
-
- return super.onKeyDown(keyCode, event);
- }
-
- private WebChromeClient mChromeClient = new WebChromeClient() {
-
- private View myView = null;
- private CustomViewCallback myCallback = null;
-
-
- @Override
- public void onGeolocationPermissionsShowPrompt(String origin,
- GeolocationPermissions.Callback callback) {
- callback.invoke(origin, true, false);
- super.onGeolocationPermissionsShowPrompt(origin, callback);
- }
-
-
- @Override
- public void onExceededDatabaseQuota(String url,
- String databaseIdentifier, long currentQuota,
- long estimatedSize, long totalUsedQuota,
- WebStorage.QuotaUpdater quotaUpdater) {
-
- quotaUpdater.updateQuota(estimatedSize * 2);
- }
-
-
- @Override
- public void onReachedMaxAppCacheSize(long spaceNeeded,
- long totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
-
- quotaUpdater.updateQuota(spaceNeeded * 2);
- }
-
-
- @Override
- public void onShowCustomView(View view, CustomViewCallback callback) {
- if (myCallback != null) {
- myCallback.onCustomViewHidden();
- myCallback = null;
- return;
- }
-
- ViewGroup parent = (ViewGroup) mWebView.getParent();
- parent.removeView(mWebView);
- parent.addView(view);
- myView = view;
- myCallback = callback;
- mChromeClient = this;
- }
-
- @Override
- public void onHideCustomView() {
- if (myView != null) {
- if (myCallback != null) {
- myCallback.onCustomViewHidden();
- myCallback = null;
- }
-
- ViewGroup parent = (ViewGroup) myView.getParent();
- parent.removeView(myView);
- parent.addView(mWebView);
- myView = null;
- }
- }
- };
-
- @SuppressLint("SetJavaScriptEnabled")
- @SuppressWarnings("deprecation")
- private void initSettings() {
-
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
-
- setContentView(R.layout.activity_main);
- mWebView = (WebView) findViewById(R.id.webview);
-
- WebSettings webSettings = mWebView.getSettings();
-
- webSettings.setJavaScriptEnabled(true);
-
-
- webSettings.setDomStorageEnabled(true);
-
-
- webSettings.setAppCacheEnabled(true);
- String appCacheDir = this.getApplicationContext()
- .getDir("cache", Context.MODE_PRIVATE).getPath();
- webSettings.setAppCachePath(appCacheDir);
- webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
- webSettings.setAppCacheMaxSize(1024 * 1024 * 10);
- webSettings.setAllowFileAccess(true);
-
-
- webSettings.setDatabaseEnabled(true);
- String databaseDir = this.getApplicationContext()
- .getDir("database", Context.MODE_PRIVATE).getPath();
- webSettings.setDatabasePath(databaseDir);
-
-
- webSettings.setGeolocationEnabled(true);
-
- webSettings.setGeolocationDatabasePath(databaseDir);
-
-
- webSettings.setPluginsEnabled(true);
- webSettings.setRenderPriority(RenderPriority.HIGH);
- webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
-
- mWebView.setWebChromeClient(mChromeClient);
- mWebView.setWebViewClient(mWebViewClient);
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- this.initSettings();
-
- mWebView.loadUrl("http://192.168.1.14/Heaven");
- }
- }