新的开发模式——webapp(1)
很久没有写过日记了,最近快要开学了,项目也基本完成了,就没有什么事儿,坐在电脑前面没事儿做,就把暑假做的项目来做一个回顾,这个项目采用了HTML5来做开发,同时外部使用了原生的APP的壳,我也就暂且将其称为WEBAPP。
我们的项目中主要应用于IOS和android系统,所以就做了安卓和苹果上的封装。之前了解过,有一个开源的打包框架——Phone Gape(好像是这么写的吧?错了也别怪我啊!),但是后来想想,使用别人的框架还不如自己来写一个,随便也复习一下自己的java知识。
在android下主要使用了webview这个控件,IOS下是使用的UIWebview。这里就先介绍下android下的,明天继续更新IOS下的使用。先直接上代码:(布局xml文件)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/webView"
/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/webView"
/>
</LinearLayout>
这个会android开发的都能看懂的,这个是申明布局一个webview用来展示html页面。
接下来就是在java代码中使用这个控件来展示,上代码(部分):
webView = (WebView)this.findViewById(R.id.webView);
//webview相关设置
webView.getSettings().setJavaScriptEnabled(true);//设置可以使用javascript
webView.getSettings().setUseWideViewPort(true);//支持用户自定义View
webView.getSettings().setDomStorageEnabled(true);//设置可以使用localStorage
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);//默认使用缓存
webView.getSettings().setAppCacheMaxSize(8*1024*1024);//缓存最多可以有8M
webView.getSettings().setAllowFileAccess(true);//可以读取文件缓存(manifest生效)
webView.setBackgroundColor(0);
webView.setBackgroundResource(R.drawable.bg_splash);
webView.getSettings().setAppCacheEnabled(true);//应用可以有缓存
webView.getSettings().setGeolocationEnabled(true);
// webView.getSettings().setBuiltInZoomControls(true);//支持缩放
webView.setInitialScale(35);//设置缩放比例
webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);//设置滚动条隐藏
//webView.setwebviewclient();
//启用地理定位
webView.getSettings().setGeolocationEnabled(true);
webView.getSettings().setRenderPriority(RenderPriority.HIGH);//设置渲染优先级
String dir = "/sdcard/temp";
//设置定位的数据库路径
webView.getSettings().setGeolocationDatabasePath(dir);
//webview相关设置
webView.getSettings().setJavaScriptEnabled(true);//设置可以使用javascript
webView.getSettings().setUseWideViewPort(true);//支持用户自定义View
webView.getSettings().setDomStorageEnabled(true);//设置可以使用localStorage
webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);//默认使用缓存
webView.getSettings().setAppCacheMaxSize(8*1024*1024);//缓存最多可以有8M
webView.getSettings().setAllowFileAccess(true);//可以读取文件缓存(manifest生效)
webView.setBackgroundColor(0);
webView.setBackgroundResource(R.drawable.bg_splash);
webView.getSettings().setAppCacheEnabled(true);//应用可以有缓存
webView.getSettings().setGeolocationEnabled(true);
// webView.getSettings().setBuiltInZoomControls(true);//支持缩放
webView.setInitialScale(35);//设置缩放比例
webView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);//设置滚动条隐藏
//webView.setwebviewclient();
//启用地理定位
webView.getSettings().setGeolocationEnabled(true);
webView.getSettings().setRenderPriority(RenderPriority.HIGH);//设置渲染优先级
String dir = "/sdcard/temp";
//设置定位的数据库路径
webView.getSettings().setGeolocationDatabasePath(dir);
这里是使用webview以及webview的相关设置,课根据实际情况进行设置。不做解释了……
这里还有一个重要的环节不要忘了,那就是根据自己的需要再配置文件中给本程序赋予相关的权限,一下是我开通的权限(有些好像是多余了的,但是又不想去删,暂且这样):
<uses-sdk android:minSdkVersion="7" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.READ_OWNER_DATA"/>
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/>
<uses-permission android:name="android.permission.DELETE_CACHE_FILES"/>
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
这样做出来的webview可以正常显示页面,但是你会发现,手机的功能键无法使用,这个时候需要重写一些方法,才能达到我们想要的目的,还是直接上代码:
//配置权限(同样在WebChromeClient中实现)
webView.setWebChromeClient(new WebChromeClient(){
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
}) ;
//设置在同一个webview中打开新的网页
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
//设置WebChromeClient
webView.setWebChromeClient(new WebChromeClient(){
//配置权限
public void onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback){
callback.invoke(origin, true, false);
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
//处理javascript中的alert
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
//构建一个Builder来显示网页中的对话框
Builder builder = new Builder(MainAcitivity.this);
builder.setTitle("提示");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
};
//处理javascript中的confirm
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
Builder builder = new Builder(MainAcitivity.this);
builder.setTitle("消息");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
};
@Override
//设置网页加载的进度条
public void onProgressChanged(WebView view, int newProgress) {
MainAcitivity.this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress * 100);
super.onProgressChanged(view, newProgress);
}
webView.setWebChromeClient(new WebChromeClient(){
public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) {
callback.invoke(origin, true, false);
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
}) ;
//设置在同一个webview中打开新的网页
webView.setWebViewClient(new WebViewClient(){
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});
//设置WebChromeClient
webView.setWebChromeClient(new WebChromeClient(){
//配置权限
public void onGeolocationPermissionsShowPrompt(String origin,GeolocationPermissions.Callback callback){
callback.invoke(origin, true, false);
super.onGeolocationPermissionsShowPrompt(origin, callback);
}
//处理javascript中的alert
public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
//构建一个Builder来显示网页中的对话框
Builder builder = new Builder(MainAcitivity.this);
builder.setTitle("提示");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
};
//处理javascript中的confirm
public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
Builder builder = new Builder(MainAcitivity.this);
builder.setTitle("消息");
builder.setMessage(message);
builder.setPositiveButton(android.R.string.ok,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.confirm();
}
});
builder.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
result.cancel();
}
});
builder.setCancelable(false);
builder.create();
builder.show();
return true;
};
@Override
//设置网页加载的进度条
public void onProgressChanged(WebView view, int newProgress) {
MainAcitivity.this.getWindow().setFeatureInt(Window.FEATURE_PROGRESS, newProgress * 100);
super.onProgressChanged(view, newProgress);
}
//设置应用程序的标题title
public void onReceivedTitle(WebView view, String title) {
MainAcitivity.this.setTitle(title);
super.onReceivedTitle(view, title);
}
});
//判断是否联网
ConnectivityManager cm;
cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean isWifiConnected=cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED;
if(!isWifiConnected){
boolean isGprsConnected=cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED;
if(!isGprsConnected){
new AlertDialog.Builder(this)
.setTitle("提示" )
.setMessage("离线状态,启用离线模式" )
.setPositiveButton("确定" , null )
.show();
}
else{
result = CallWCF();
}
}
//有网络,检查是否有可更新
//if(info==null|| !info.isAvailable()){
//}
//与远程服务器通信,并接收返回的字符串
/* try{
//long a=System.currentTimeMillis();
url = new URL(strUrl);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setConnectTimeout(1000);
urlConn.setReadTimeout(1000);
InputStreamReader in = new InputStreamReader(urlConn.getInputStream());
BufferedReader bufferedReader = new BufferedReader(in);
while((readLine = bufferedReader.readLine())!=null){
result+=readLine;
}
in.close();
urlConn.disconnect();
}catch(UnsupportedEncodingException e){
e.printStackTrace();
}catch(MalformedURLException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}*/
//这里来检测版本是否需要更新
else{
result = CallWCF();
}
//System.out.println(result);
String[] url_tmp=null;
url_tmp =result.split("\"");
if(url_tmp[3].equals("yes")){
}
else{
result = "http://192.168.1.104:3001/Admin/BaseManagement/ClientVersion/Client/"+url_tmp[3];
//执行更新程序
mUpdateManager = new UpdateManager(this);
mUpdateManager.checkUpdateInfo(result);
}
//添加拨打电话的JS脚本
webView.addJavascriptInterface(this, "callPhone");
webView.loadUrl("file:///android_asset/Htmls/Index.html");//连接assets文件夹下的首页HTML文件
}
// 设置返回功能
public boolean onKeyDown(int keyCoder,KeyEvent event){
if(keyCoder == KeyEvent.KEYCODE_BACK){
if(webView.canGoBack()){
webView.goBack();
return true;
}
else{
AlertDialog.Builder builder = new Builder(this);
builder.setMessage("确认退出本系统吗?");
public void onReceivedTitle(WebView view, String title) {
MainAcitivity.this.setTitle(title);
super.onReceivedTitle(view, title);
}
});
//判断是否联网
ConnectivityManager cm;
cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
boolean isWifiConnected=cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState() == NetworkInfo.State.CONNECTED;
if(!isWifiConnected){
boolean isGprsConnected=cm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState() == NetworkInfo.State.CONNECTED;
if(!isGprsConnected){
new AlertDialog.Builder(this)
.setTitle("提示" )
.setMessage("离线状态,启用离线模式" )
.setPositiveButton("确定" , null )
.show();
}
else{
result = CallWCF();
}
}
//有网络,检查是否有可更新
//if(info==null|| !info.isAvailable()){
//}
//与远程服务器通信,并接收返回的字符串
/* try{
//long a=System.currentTimeMillis();
url = new URL(strUrl);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setConnectTimeout(1000);
urlConn.setReadTimeout(1000);
InputStreamReader in = new InputStreamReader(urlConn.getInputStream());
BufferedReader bufferedReader = new BufferedReader(in);
while((readLine = bufferedReader.readLine())!=null){
result+=readLine;
}
in.close();
urlConn.disconnect();
}catch(UnsupportedEncodingException e){
e.printStackTrace();
}catch(MalformedURLException e){
e.printStackTrace();
}catch(IOException e){
e.printStackTrace();
}*/
//这里来检测版本是否需要更新
else{
result = CallWCF();
}
//System.out.println(result);
String[] url_tmp=null;
url_tmp =result.split("\"");
if(url_tmp[3].equals("yes")){
}
else{
result = "http://192.168.1.104:3001/Admin/BaseManagement/ClientVersion/Client/"+url_tmp[3];
//执行更新程序
mUpdateManager = new UpdateManager(this);
mUpdateManager.checkUpdateInfo(result);
}
//添加拨打电话的JS脚本
webView.addJavascriptInterface(this, "callPhone");
webView.loadUrl("file:///android_asset/Htmls/Index.html");//连接assets文件夹下的首页HTML文件
}
// 设置返回功能
public boolean onKeyDown(int keyCoder,KeyEvent event){
if(keyCoder == KeyEvent.KEYCODE_BACK){
if(webView.canGoBack()){
webView.goBack();
return true;
}
else{
AlertDialog.Builder builder = new Builder(this);
builder.setMessage("确认退出本系统吗?");
builder.setTitle("提示");
builder.setPositiveButton("确认", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain); System.exit(0);
public void onClick(DialogInterface dialog, int which) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain); System.exit(0);
dialog.dismiss();
//this.finish();
}
});
//this.finish();
}
});
builder.setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
}
return false;
}
//调用拨号器
public void call(String mobile){
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ mobile));
startActivity(intent);
}
// }
//构造菜单
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, indexItem, 0, "首页").setIcon(R.drawable.index); //设置图标
menu.add(0, exitItem, 0, "退出").setIcon(R.drawable.exit);
return true;
}
private String CallWCF() {
HttpEntity responseEntity = null ;
}
}
return false;
}
//调用拨号器
public void call(String mobile){
Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:"+ mobile));
startActivity(intent);
}
// }
//构造菜单
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, indexItem, 0, "首页").setIcon(R.drawable.index); //设置图标
menu.add(0, exitItem, 0, "退出").setIcon(R.drawable.exit);
return true;
}
private String CallWCF() {
HttpEntity responseEntity = null ;
try {
// Send GET request to <service>/GetPlates
HttpGet request = new HttpGet("http://192.168.1.104:3001/MobileBankingService.svc/GetLastVersion?Bh=01001&OS=Android");
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
responseEntity = response.getEntity();
} catch (Exception e) {
e.printStackTrace();
}
return retrieveInputStream(responseEntity);
}
//接受数据
protected String retrieveInputStream(HttpEntity httpEntity) {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(request);
responseEntity = response.getEntity();
} catch (Exception e) {
e.printStackTrace();
}
return retrieveInputStream(responseEntity);
}
//接受数据
protected String retrieveInputStream(HttpEntity httpEntity) {
int length = (int) httpEntity.getContentLength();
if (length < 0)
length = 10000;
StringBuffer stringBuffer = new StringBuffer(length);
try {
InputStreamReader inputStreamReader = new InputStreamReader(
httpEntity.getContent(), HTTP.UTF_8);
char buffer[] = new char[length];
int count;
//String buf;
while ((count = inputStreamReader.read(buffer, 0, length - 1)) > 0) {
stringBuffer.append(buffer, 0, count);
//buf = .substring(6,8);
}
} catch (UnsupportedEncodingException e) {
} catch (IllegalStateException e) {
} catch (IOException e) {
}
return stringBuffer.toString();
}
if (length < 0)
length = 10000;
StringBuffer stringBuffer = new StringBuffer(length);
try {
InputStreamReader inputStreamReader = new InputStreamReader(
httpEntity.getContent(), HTTP.UTF_8);
char buffer[] = new char[length];
int count;
//String buf;
while ((count = inputStreamReader.read(buffer, 0, length - 1)) > 0) {
stringBuffer.append(buffer, 0, count);
//buf = .substring(6,8);
}
} catch (UnsupportedEncodingException e) {
} catch (IllegalStateException e) {
} catch (IOException e) {
}
return stringBuffer.toString();
}
//监听菜单选项
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case indexItem:
// setTitle("单击了菜单子项1");
webView.loadUrl("file:///android_asset/Htmls/Index.html");
break;
case exitItem:
//setTitle("单击了菜单子项2");
AlertDialog.Builder builder = new Builder(this);
builder.setMessage("确认退出本系统吗?");
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case indexItem:
// setTitle("单击了菜单子项1");
webView.loadUrl("file:///android_asset/Htmls/Index.html");
break;
case exitItem:
//setTitle("单击了菜单子项2");
AlertDialog.Builder builder = new Builder(this);
builder.setMessage("确认退出本系统吗?");
builder.setTitle("提示");
builder.setPositiveButton("确认", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain); System.exit(0);
public void onClick(DialogInterface dialog, int which) {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(startMain); System.exit(0);
dialog.dismiss();
//this.finish();
}
});
//this.finish();
}
});
builder.setNegativeButton("取消", new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
break;
}
return true;
}
break;
}
return true;
}
}
到此android下的webapp的框架基本完成,以上代码有很多不完整的,我的电脑上有成熟的框架了,只需要把需要展示的html加入到项目就可以生成一个应用程序,并且应用程序的返回、退出、主页功能都完善,如果有需要的可以向我索要,嘿嘿……奉献一盘。