这篇文章简单学习了混合开发框架Appcan的Engine是如何解析widget的配置文件config.xml。文中的源码参考官方开源项目appcan-android
首先, 在application类中调用Appcan.class
的initSync(context)
方法进行同步初始化,在该方法中判断assets目录中是否有rootWidget(所谓的rootWidget就是文件夹名字为widget
的widget),判断的标准就是widget
目录中是否含有config.xml
文件。如果有则调用getWidgetData()
解析config.xml
文件,否则获取默认的widget,默认的widget
就是new了一个WWidgetData对象, 然后为该对象的 m_appId、m_indexUrl属性赋上默认值。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 if (wDataManager.isHasAssetsWidget()) {
mWidgetData = wDataManager.getWidgetData();
} else {
mWidgetData = wDataManager.getDefaultWidgetData();
}
/**
* 获取默认的widget
* @return
*/
public WWidgetData getDefaultWidgetData() {
WWidgetData widgetData = new WWidgetData();
widgetData.m_appId = "default";
widgetData.m_indexUrl = "index.html";
return widgetData;
}
重点分析getWidgetData() 和 getWidgetDataByXML(path,type).
getWidgetDataByXML(path,type)的作用就是解析config.xml ,解析完成后返回一个WWidgetData对象.
getWidgetData()
该方法会首先调用 getWidgetDataByXML(path,type) ,解析路径 assets目录中文件夹名字为widget的微应用,该widget就是rootWidget.
1 | //m_rootWidgetConfigPath为 widget/config.xml |
然后调用checkAppStatus(context, appid)来判断是widget是否需要更新,如果isUpdateWidget为true, 则开启一个线程复制asssets目录中的rootwidget到 /data/data/files/widget/
中.
heckAppStatus是如何判断的,这点自己还不是很理解,但是需要注意一点:appstatus 属性是在 values文件的Strings.xml中进行配置,appkey也是在该文件中配置的.
1 | <string name="appstatus" translatable="false">6E4E99740100CFB7447DAB9CCC55DD75F7D658</string> |
接下来 如果有增量更新包,且其版本号大于当前APK的版本号,则进行同步拷贝操作,防止再次弹出增量更新提示框,否则,才进行异步拷贝操作. 这里的逻辑比较复杂,暂时不做研究.
getWidgetDataByXML(path,type)
这个方法比较重要,主要解析config.xml配置文件,返回一个 WWidgetData 对象.
1. 解析config.xml文件返回widgetData对象
首先判断path
是否是以”/“开头,
- 如果是,表示传入的是一个普通的路径,创建一个file对象,然后调用getWidgetDataOfXML(inputStream)
- 如果不是,则表示是在assets目录中,则根据assets中的路径,调用getWidgetDataOfXML(inputStream)
这两种情况最终调用的都是getWidgetDataOfXML(inputStream)来解析config.xml
文件的。
1 | if (!path.startsWith("/")) { |
2. 解析 widgetPath 属性
当path 以 “/“开头说明该widget不是assets中的widget。
如果不是以”/“开头,则说明是一个assets widget, 如果此时type为3的话是一个普通的assets widget, 否则则是一个rootwidget
1 | if (!path.startsWith("/")) { |
如果是以 “/“开头,则widgetPath如下:
1
widgetPath = file:// + file.getParentFile().getAbsolutePath() + "/";
如果不是以 “/“开头,则说明该widget是assets中的widget,然后根据type判断是否是rootWidget
type 为3,widgetPath为如下内容,说明该widget是一个普通的widget
1
widgetPath = file:///android_asset/ + path.substring(0, path.lastIndexOf('/') + 1);
type 不为3,说明该widget是一个rootwidget
1
widgetPath = file:///android_asset/ + widget/ ;
3. 解析m_indexUrl 和m_iconPath 属性
如果 m_indexUrl 为”#” 或者为空时,m_indexUrl 默认为 widgetPath + “index.html”,也就是widget默认打开的首页为widget的根目录中的index.html页面。
否则m_indexUrl值为:将config.xml 解析得到的 m_indexUrl(config.xml中配置的src 属性的值)和widgetPath拼接后得到新的 widgetData.m_indexUrl属性值,也就是打开的首页为config.xml 中 配置的首页。
iconPath 的解析和 indexUrl的解析过程一样。
1 | if ("#".equals(widgetData.m_indexUrl) |
4. 设置 m_widgetPath属性的值
根据上边解析的widgetPath 和传入的type的值来设置widgetData.m_widgetPath的值.此处也要注意,
1 | //type不为3 表示的是一个rootWidget |
type为3的话,说明是rootWidget, 将widgetPath的协议头 file://
去掉,此时 m_widgetPath 的格式为/android_asset/ + path
,
如果type不为3, 则调用getWidgetPath(type, widgetData.m_appId)
,返回一个路径。
4.1 解析rootWidget的 widgetPath
getWidgetPath(int type, String appId)
是根据type的值用来解析普通widget的widgetPath
。
1 |
|
如上代码:
首先解析appPath的值,如果type为0或1, appPath为 ` widgetone/apps/`,否则appPath为 `widgetone/widgets/`。
然后解析appIdPath的值, 如果appId为 "9999999" , 则appIdPath为 "9999999",否则appidPath为 appid 。
然后根据 isWidgetOneSBox 判断是否是沙箱路径,
如果是沙箱环境,则根路径为 sd卡的根路径拼接上appPath和appidPath,
否则根路径为`/data/data/packageName/files/`拼接上appPath和appidPath。
如果是则该路径, type =1 ,则在根路径的基础上拼接 `myspace`
总结
解析config.xml
的步骤大致总结如下:
在AppCan.java
的初始化方法initSync
中首先判断assets
目录中是有名字为wdiget
的文件夹,如果有则说明存在rootWidget,然后解析config.xml文件;否则不存在rootwidget, 创建一个 wDataManager对象,为m_appId和m_indexUrl赋默认值。
然后调用getWidgetDataByXML(String path, int type)
解析config.xml。
在该方法中首先调用 getWidgetDataOfXML
对 config.xml
解析。
然后解析widgetPath属性。
判断根据`path`是否是以"/"开头
如果是,则说明该widget不是assets中的widget, 然后拼接`file://`前缀.
如果不是,则拼接`file:///android_asset/`。
然后判断type是否为3,如果为3则说明是rootWidget。
如果不为3,则说明是assets中的普通的widget。
接着,根据上一步解析的widgetPath来拼接m_indexUrl 和m_iconPath 属性。
最后在根据解析的 widgetPath 属性来给 widgetData的 m_wgtType 属性赋值。
根据type是否为3来为 m_wgtType 属性复制
如果为3, 则说明是一个rootWidget, 则将 widgetPath 前边的 file:// 去掉,最终格式为`/android_asset/ + path`
如果不为3 ,首先会根据type的值(0/1/其它)来设置appPath,根据appId来设置appIdPath的值。 然后将根路径拼接上appPath和appidPath,得到最终的值。
(沙箱环境的根路径为/data/data/packageName/files/`,非沙箱环境的根路径为sd卡的根路径)。
可以看到,如果是type为3,则说明是rootWidget,该rootWidget存放在assets目录中的widget文件夹中。 m_wgtType 是以"file:///android_asset/" 开头的,
如果type不为3,则会根据是否是沙箱环境设置不同的路径。
博客编号: 26