上一篇讲述了cordova
工程的创建,并成功运行起来,那cordova是如何加载html页面的,本文就来详细分析一下。
MainActivity
分析
App的入口是MainActivity
,打开MainActivity
可以看到是继承于CordovaActivity
,在onCreate中的loadUrl
方法和launchUrl
属性都是从CordovaActivity
中继承来的,所以CordovaActivity
是cordova
的入口。
public class MainActivity extends CordovaActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// enable Cordova apps to be started in the background
// 获取外部传来的数据
Bundle extras = getIntent().getExtras();
if (extras != null && extras.getBoolean("cdvStartInBackground", false)) {
moveTaskToBack(true);
}
// 加载html
// Set by <content src="index.html" /> in config.xml
loadUrl(launchUrl);
}
}
CordovaActivity
分析
一、OnCreate方法
进入CordovaActivity
类,可以看到CordovaActivity
继承于Activity
,这个类主要是完成对cordova的基本配置和初始化工作,根据Activity的生命周期,先从OnCreate开始分析:
1、在OnCreate中第一个方法是loadConfig
方法,如下所示:
protected void loadConfig() {
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(this);
preferences = parser.getPreferences();
preferences.setPreferencesBundle(getIntent().getExtras());
launchUrl = parser.getLaunchUrl();
pluginEntries = parser.getPluginEntries();
Config.parser = parser;
}
loadConfig方法首先初始化了ConfigXmlParser
类,而ConfigXmlParser
的主要属性和方法有:
CordovaPreferences
类:负责解析config.xml
的<preference name="loglevel" value="DEBUG" />
节点;launchUrl
属性值:默认是file:///android_asset/www/index.html
;- setStartUrl方法:判断
config.xml
中是否配置了<content src="index.html" />
; parse
方法:解析了res/xml目录下的config.xml
文件
2、初始化完配置,接着初始化日志,设置日志级别。
String logLevel = preferences.getString("loglevel", "ERROR");
LOG.setLogLevel(logLevel);
3、再往下就是配置窗口是否全屏,是否有标题。
if (!preferences.getBoolean("ShowTitle", false)) {
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
}
if (preferences.getBoolean("SetFullscreen", false)) {
LOG.d(TAG, "The SetFullscreen configuration is deprecated in favor of Fullscreen, and will be removed in a future version.");
preferences.set("Fullscreen", true);
}
if (preferences.getBoolean("Fullscreen", false)) {
// NOTE: use the FullscreenNotImmersive configuration key to set the activity in a REAL full screen
// (as was the case in previous cordova versions)
if (!preferences.getBoolean("FullscreenNotImmersive", false)) {
immersiveMode = true;
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
}
二、loadUrl方法
loadUrl方法是在MainActivity中调用的,这个方法的实现如下所示:
public void loadUrl(String url) {
if (appView == null) {
init();
}
// If keepRunning
this.keepRunning = preferences.getBoolean("KeepRunning", true);
appView.loadUrlIntoView(url, true);
}
这个方法首先执行了init()
方法,在init方法中创建了appView也就是webview实例,执行方法如下:
appView = makeWebView();
而makeWebView()方法里实现了CordovaWebViewImpl
实例,顾名思义,这个类是CordovaWebView
的实现类,这个类留着以后讲。
protected CordovaWebView makeWebView() {
return new CordovaWebViewImpl(makeWebViewEngine());
}
protected CordovaWebViewEngine makeWebViewEngine() {
return CordovaWebViewImpl.createEngine(this, preferences);
}
创建了webview的实例appView
,接着就是设置CordovaActivity的布局,执行的方法是createViews()
,设置完布局,再往下执行appView的初始化和cordovaInterface的初始化,这些类都在以后讲。
看完了init方法,再往下就是使用webview加载html的url了
appView.loadUrlIntoView(url, true);
三、Activity生命周期方法
CordovaActivity中的关键方法就是上述的那些,当然还有许多方法,不过都是些继承方法,下面列举一下:
- onPause
- onNewIntent
- onResume
- onStop
- onStart
- onDestroy
这些都是Activity的生命周期方法,在这些方法中,都实现了webview对应的方法,这些方法其实是对插件的处理。如:
@Override
protected void onStart() {
super.onStart();
LOG.d(TAG, "Started the activity.");
if (this.appView == null) {
return;
}
this.appView.handleStart();
}
在CordovaActivity的onStart方法中执行了this.appView.handleStart();
方法,而handleStart
方法中实现了
@Override
public void handleStart() {
if (!isInitialized()) {
return;
}
pluginManager.onStart();
}
这些以后在分析CordovaWebViewImpl
这个类的时候再详细说明。
四、Activity继承方法
除了生命周期方法,还有
- startActivityForResult
- onActivityResult
- onRequestPermissionsResult
- onSaveInstanceState
- onWindowFocusChanged
- onConfigurationChanged
- onOptionsItemSelected
- onPrepareOptionsMenu
- onCreateOptionsMenu
这些都是Activity的继承方法,大家都很熟悉就不做讲解了。
四、onReceivedError继承方法
下面再讲一个比较重要的方法:错误处理页面。
在CordovaActivity中有个onReceivedError
方法,这个方法就是处理当前html页面报错了,会跳转到另一个页面显示错误提示信息,类似于访问网页找不到的时候,显示一个404页面。
public void onReceivedError(final int errorCode, final String description, final String failingUrl) {
final CordovaActivity me = this;
// If errorUrl specified, then load it
final String errorUrl = preferences.getString("errorUrl", null);
if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {
// Load URL on UI thread
me.runOnUiThread(new Runnable() {
public void run() {
me.appView.showWebPage(errorUrl, false, true, null);
}
});
}
// If not, then display error dialog
else {
final boolean exit = !(errorCode == WebViewClient.ERROR_HOST_LOOKUP);
me.runOnUiThread(new Runnable() {
public void run() {
if (exit) {
me.appView.getView().setVisibility(View.GONE);
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
}
}
});
}
}
这个方法处理逻辑是,判断是否在config.xml
页面配置了errorUrl
,如果配置了errorUrl,那么就跳转到这个url指向的html页面,如下所示:
me.appView.showWebPage(errorUrl, false, true, null);
如果没配置就隐藏掉webview,并调用displayError
方法
me.appView.getView().setVisibility(View.GONE);
me.displayError("Application Error", description + " (" + failingUrl + ")", "OK", exit);
displayError
方法的实现很简单,其实就是创建一个AlertDialog来提示信息。
public void displayError(final String title, final String message, final String button, final boolean exit) {
final CordovaActivity me = this;
me.runOnUiThread(new Runnable() {
public void run() {
try {
AlertDialog.Builder dlg = new AlertDialog.Builder(me);
dlg.setMessage(message);
dlg.setTitle(title);
dlg.setCancelable(false);
dlg.setPositiveButton(button,
new AlertDialog.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
if (exit) {
finish();
}
}
});
dlg.create();
dlg.show();
} catch (Exception e) {
finish();
}
}
});
}
到此,CordovaActivity的分析结束,可能还有些细节没分析到,这些就留给大家自己思考吧。