Android用PhoneGap封装webapp在android代码中实现连按退出和loadingpage
用PhoneGap封装后的程序有一些瑕疵,比如启动时黑屏,菜单按钮和返回按钮不好控制等。
PhoneGap也在github提交的它的源码(版本:2.8):
https://github.com/apache/cordova-android/tree/master/framework/src/org/apache/cordova
先说loadingpage,其实在phonegap提供的api中已经提供了设置的方法:
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); super.setIntegerProperty("loadUrlTimeoutValue",30 * 1000); //设定loadingpage背景 super.setIntegerProperty("splashscreen", R.drawable.bg); //判断网络是否可用,不可用直接转到相关错误提示页面 ConnectivityManager cwjManager=(ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE); NetworkInfo netInfo = cwjManager.getActiveNetworkInfo(); if(null != netInfo && netInfo.isAvailable()){ super.loadUrl("http://xx.com/index.html", 10000); }else{ super.loadUrl("file:///android_asset/www/error.html", 3000); } }
注意在访问网络地址时,必须调用有2个参数的loadurl方法才会显示背景图,即:
super.loadUrl("http://xx.com/index.html", 10000);
通过看CordovaActivity(你的Activity需要集成的基础Activity)的源码知道2个参数和1个参数的loadurl内容是不一样的。
这样设置后,又出现了一个问题,第二个参数timeout表示背景图显示的时间,不管页面是否加载完,总是会显示给定的时间,哪怕你的应用1秒就已加载完成了。通过大量的观察后,发现在logcat里面有这么一句:
06-24 15:17:35.060: D/DroidGap(30429): onMessage(onPageFinished,http://xx.com/index.html)
推测在页面加载完成后,会调用CordovaActivity的onMessage方法,并且参数分别是onPageFinished和http://xx.com/index.html。在结合源码,发现在onMessage中对有些参数id的动作有所处理,如“splashscreen”,“spinner”。但是没有对“onPageFinished”的处理。
所以考虑在自己的activity中重写该方法,对“onPageFinished”有所处理:
@Override public Object onMessage(String id, Object data) { if(id.equals("onPageFinished")){ this.removeSplashScreen(); return null; } return super.onMessage(id, data); }
这样loadingpage的显示时间就会和加载时间相同了。
对于按钮的控制:
通常会对app做"再按一次退出程序"的处理,但是发现用通常的重写keydown事件的方法时,程序并不是那么听话。在其他页面时,会返回,不能在返回时就退出了。内嵌浏览器的痕迹明显。通过观察源码也可以知道,在CordovaActivity中有一个继承自WebView的CordovaWebView。在观察CordovaWebView的源码,发现它对程序的keydown和keyup的事件重写了:
@Override public boolean onKeyUp(int keyCode, KeyEvent event) { // If back key if (keyCode == KeyEvent.KEYCODE_BACK) { // A custom view is currently displayed (e.g. playing a video) if(mCustomView != null) { this.hideCustomView(); } else { // The webview is currently displayed // If back key is bound, then send event to JavaScript if (this.bound) { this.loadUrl("javascript:cordova.fireDocumentEvent('backbutton');"); return true; } else { // If not bound // Go to previous page in webview if it is possible to go back if (this.backHistory()) { return true; } // If not, then invoke default behaviour else { //this.activityState = ACTIVITY_EXITING; //return false; // If they hit back button when app is initializing, app should exit instead of hang until initilazation (CB2-458) this.cordova.getActivity().finish(); } } } } // Legacy else if (keyCode == KeyEvent.KEYCODE_MENU) { if (this.lastMenuEventTime < event.getEventTime()) { this.loadUrl("javascript:cordova.fireDocumentEvent('menubutton');"); } this.lastMenuEventTime = event.getEventTime(); return super.onKeyUp(keyCode, event); } // If search key else if (keyCode == KeyEvent.KEYCODE_SEARCH) { this.loadUrl("javascript:cordova.fireDocumentEvent('searchbutton');"); return true; } else if(keyUpCodes.contains(keyCode)) { //What the hell should this do? return super.onKeyUp(keyCode, event); } //Does webkit change this behavior? return super.onKeyUp(keyCode, event); }
//由于退出功能在onkeyup,所以只关心onkeyup
还是老办法,自己实现一个继承自CordovaWebView的webview,重写onkeyup方法:
import java.util.Timer; import java.util.TimerTask; import org.apache.cordova.CordovaWebView; import android.content.Context; import android.util.AttributeSet; import android.view.KeyEvent; import android.widget.Toast; /** * 当按下返回按钮是提示再按退出,而不是返回 * @author Lee */ public class NobackWebView extends CordovaWebView { public NobackWebView(Context context) { super(context); } public NobackWebView(Context context, AttributeSet attrs) { super(context, attrs); } public NobackWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public NobackWebView(Context context, AttributeSet attrs, int defStyle, boolean privateBrowsing) { super(context, attrs, defStyle, privateBrowsing); } @Override public boolean onKeyUp(int keyCode, KeyEvent event){ if (keyCode == KeyEvent.KEYCODE_BACK) { exitBy2Click(); return true; }else{ return super.onKeyUp(keyCode, event); } } public void toastMessage(String msg, int duration) { Toast.makeText(this.getContext(), msg, duration).show(); } private static Boolean isExit = false; private void exitBy2Click() { Timer tExit = null; if (isExit == false) { isExit = true; // 准备退出 toastMessage("再按一次退出程序", 2000); tExit = new Timer(); tExit.schedule(new TimerTask() { @Override public void run() { isExit = false; // 取消退出 } }, 2000); // 如果2秒钟内没有按下返回键,则启动定时器取消掉刚才执行的任务 } else { System.exit(0); } } }
这样在app中就可以实现"再按一次退出程序"的功能了。
还剩下最后一个步骤就是将CordovaActivity中的webview替换成自己的webview,老办法,在自己的activity中重写init方法:
@Override public void init() { //只是把源码中的CordovaWebView换成NobackWebView,其他还是源码 CordovaWebView webView = new NobackWebView(this); CordovaWebViewClient webViewClient; if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.HONEYCOMB) { webViewClient = new CordovaWebViewClient(this, webView); } else { webViewClient = new IceCreamCordovaWebViewClient(this, webView); } this.init(webView, webViewClient, new CordovaChromeClient(this, webView)); }
这样就大功告成了。菜单按钮的操作也是类似的方法,就不介绍了,如果像实现返回按钮还是执行返回动作,只是在首页时才提示退出,可以参考源码,在重写的方法中调用返回方法,在首页时退出。
以上的方法只是针对js不熟或不喜欢js处理的同学,因为PhoneGap在js代码中提供的相似的功能,比如loadingpage的关闭可以在设备初始化后调用:navigator.splashscreen.hide();方法。菜单,返回按钮的操作可以在js中注册等,这些网上应该比较多,就不介绍了。