通过cordova plugin add **
添加插件,会将插件信息写入config.xml中。
<plugin name="cordova-hot-code-push-plugin" spec="^1.5.3" />
=转换
=>
config.xml真实地址 platforms\android\app\src\main\res\config.xml
<feature name="HotCodePush">
<param name="android-package" value="com.nordnetab.chcp.main.HotCodePushPlugin" />
<param name="onload" value="true" />
</feature>
CordovaActivity
protected void loadConfig() {
ConfigXmlParser parser = new ConfigXmlParser();
parser.parse(this);//解析config.xml中的属性与插件信息(PluginEntery)
preferences = parser.getPreferences();
preferences.setPreferencesBundle(getIntent().getExtras());
launchUrl = parser.getLaunchUrl();
pluginEntries = parser.getPluginEntries();//获得解析的插件信息(此时还未实例化插件)
Config.parser = parser;
}
public void loadUrl(String url) {
if (appView == null) {
init();//相关实例化(插件)
}
// If keepRunning
this.keepRunning = preferences.getBoolean("KeepRunning", true);
appView.loadUrlIntoView(url, true);
}
protected void init() {
appView = makeWebView();
createViews();
if (!appView.isInitialized()) {
appView.init(cordovaInterface, pluginEntries, preferences);
}
cordovaInterface.onCordovaInit(appView.getPluginManager());
// Wire the hardware volume controls to control media if desired.
String volumePref = preferences.getString("DefaultVolumeStream", "");
if ("media".equals(volumePref.toLowerCase(Locale.ENGLISH))) {
setVolumeControlStream(AudioManager.STREAM_MUSIC);
}
}
ConfigXmlParser
public void parse(Context action) {
// First checking the class namespace for config.xml
int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName());
if (id == 0) {
// If we couldn't find config.xml there, we'll look in the namespace from AndroidManifest.xml
id = action.getResources().getIdentifier("config", "xml", action.getPackageName());
if (id == 0) {
LOG.e(TAG, "res/xml/config.xml is missing!");
return;
}
}
parse(action.getResources().getXml(id));//加载config.xml并解析
}
public void parse(XmlPullParser xml) {//解析config.xml中的属性(content ,index ,plugin)
int eventType = -1;
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
handleStartTag(xml);//config.xml解析(插件,content)
}
else if (eventType == XmlPullParser.END_TAG)
{
handleEndTag(xml);
}
try {
eventType = xml.next();
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void handleStartTag(XmlPullParser xml) {
String strNode = xml.getName();
if (strNode.equals("feature")) {//读取到插件标签
//Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc)
//Set the bit for reading params
insideFeature = true;
service = xml.getAttributeValue(null, "name");//获得插件定义的文件名
}
else if (insideFeature && strNode.equals("param")) {
paramType = xml.getAttributeValue(null, "name");
if (paramType.equals("service")) // check if it is using the older service param
service = xml.getAttributeValue(null, "value");
else if (paramType.equals("package") || paramType.equals("android-package"))
pluginClass = xml.getAttributeValue(null,"value");//获取插件类路径
else if (paramType.equals("onload"))
onload = "true".equals(xml.getAttributeValue(null, "value"));//获取插件是否默认加载
}
}
public void handleEndTag(XmlPullParser xml) {
String strNode = xml.getName();
if (strNode.equals("feature")) {
//PluginEntry 将插件信息保存在pluginentry中,之后会用到PluginManager进行实例化
pluginEntries.add(new PluginEntry(service, pluginClass, onload));
service = "";
pluginClass = "";
insideFeature = false;
onload = false;
}
}
//获得解析的插件
public ArrayList<PluginEntry> getPluginEntries() {
return pluginEntries;
}
CordovaWebViewImpl
public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences) {
//...
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
resourceApi = new CordovaResourceApi(engine.getView().getContext(), pluginManager);
nativeToJsMessageQueue = new NativeToJsMessageQueue();
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.NoOpBridgeMode());
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.LoadUrlBridgeMode(engine, cordova));
if (preferences.getBoolean("DisallowOverscroll", false)) {
engine.getView().setOverScrollMode(View.OVER_SCROLL_NEVER);
}
engine.init(this, cordova, engineClient, resourceApi, pluginManager, nativeToJsMessageQueue);
// This isn't enforced by the compiler, so assert here.
assert engine.getView() instanceof CordovaWebViewEngine.EngineView;
pluginManager.addService(CoreAndroid.PLUGIN_NAME, "org.apache.cordova.CoreAndroid");
pluginManager.init();
}
PluginManager
public void init() {//插件初始化
LOG.d(TAG, "init()");
isInitialized = true;
this.onPause(false);
this.onDestroy();
pluginMap.clear();//插件清空
this.startupPlugins();//插件实例化
}
private void startupPlugins() {
for (PluginEntry entry : entryMap.values()) {
// Add a null entry to for each non-startup plugin to avoid ConcurrentModificationException
// When iterating plugins.
if (entry.onload) {
getPlugin(entry.service);
} else {
pluginMap.put(entry.service, null);
}
}
}
public CordovaPlugin getPlugin(String service) {
CordovaPlugin ret = pluginMap.get(service);
if (ret == null) {//如果插件未实例化,则进行实例化
PluginEntry pe = entryMap.get(service);
if (pe == null) {
return null;
}
if (pe.plugin != null) {
ret = pe.plugin;
} else {
ret = instantiatePlugin(pe.pluginClass);//插件实例化
}
ret.privateInitialize(service, ctx, app, app.getPreferences());
pluginMap.put(service, ret);
}
return ret;
}