Small 的集成异常简单,只需要在项目下的 build.gradle 文件dependencies 中添加 Small 编译插件 gradle-small:
classpath 'net.wequick.tools.build:gradle-small:1.3.0-beta2'
复制代码
并且在文件末尾引用插件:
apply plygin: 'net.wequick.small'
复制代码
但 Small 对于项目结构的要求比较严格,比如宿主最好就是刚开始新建项目时候的 app 应用,这个名字最好不要改,Small 会通过名字来寻找宿主和插件。插件业务模块命名以 app.* 和lib.* 作开头,包名最好也要以 app.或者 app 结尾,插件业务模块都是可以单独打包的模块,这些模块和 app 一样.
然后在/assets/bundle.json文件中注册自己的所有模块
{
"version": "1.0.0",
"bundles": [
{
"uri": "lib.utils",
"pkg": "net.wequick.example.small.lib.utils"
},
{
"uri": "lib.style",
"pkg": "com.example.mysmall.lib.style"
},
{
"uri": "lib.analytics",
"pkg": "net.wequick.example.lib.analytics"
},
{
"uri": "main",
"pkg": "net.wequick.example.small.app.main"
},
{
"uri": "home",
"pkg": "net.wequick.example.small.app.home"
},
{
"uri": "mine",
"pkg": "net.wequick.example.small.app.mine"
},
{
"uri": "detail",
"pkg": "net.wequick.example.small.app.detail",
"rules": {
"sub": "Sub"
}
},
{
"uri": "stub",
"type": "app",
"pkg": "net.wequick.example.small.appok_if_stub"
},
{
"uri": "about",
"pkg": "net.wequick.example.small.web.about"
}
]
}
复制代码
跳转其他Activity
默认的跳转是跳转到启动页面,传递参数的形式和GET请求一样
跳转指定的activity
先buildlib后buildBundle
small也可以实现热修复的功能
public class UpgradeManager {
private static class UpdateInfo {
public String packageName;
public String downloadUrl;
}
private static class UpgradeInfo {
public JSONObject manifest;
public List<UpgradeManager.UpdateInfo> updates;
}
private interface OnResponseListener {
void onResponse(UpgradeManager.UpgradeInfo info);
}
private interface OnUpgradeListener {
void onUpgrade(boolean succeed);
}
private static class ResponseHandler extends Handler {
private UpgradeManager.OnResponseListener mListener;
public ResponseHandler(UpgradeManager.OnResponseListener listener) {
mListener = listener;
}
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
mListener.onResponse((UpgradeManager.UpgradeInfo) msg.obj);
break;
}
}
}
private UpgradeManager.ResponseHandler mResponseHandler;
private Context mContext;
private ProgressDialog mProgressDlg;
public UpgradeManager(Context context) {
mContext = context;
}
public void checkUpgrade() {
//mProgressDlg = ProgressDialog.show(mContext, "Small", "Checking for updates...");
requestUpgradeInfo(Small.getBundleVersions(), new OnResponseListener() {
@Override public void onResponse(UpgradeInfo info) {
//mProgressDlg.setMessage("Upgrading...");
upgradeBundles(info, new OnUpgradeListener() {
@Override public void onUpgrade(boolean succeed) {
//mProgressDlg.dismiss();
//mProgressDlg = null;
String text = succeed
? "Upgrade Success! Switch to background and back to foreground to see changes."
: "Upgrade Failed!";
Log.i("tag", "===========" + text);
Toast.makeText(mContext, text, Toast.LENGTH_SHORT).show();
}
});
}
});
}
/**
*
* @param versions
* @param listener
*/
private void requestUpgradeInfo(Map versions, UpgradeManager.OnResponseListener listener) {
System.out.println(versions); // this should be passed as HTTP parameters
mResponseHandler = new UpgradeManager.ResponseHandler(listener);
new Thread() {
@Override public void run() {
try {
// 换成自己服务器地址
// Json format see http://wequick.github.io/small/upgrade/bundles.json
URL url = new URL("http://incoidea.incopat.com/appservice/resources/bundle.json");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
StringBuilder sb = new StringBuilder();
InputStream is = conn.getInputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
sb.append(new String(buffer, 0, length));
}
// Parse json
JSONObject jo = new JSONObject(sb.toString());
JSONObject mf = jo.has("manifest") ? jo.getJSONObject("manifest") : null;
JSONArray updates = jo.getJSONArray("updates");
int N = updates.length();
List<UpgradeManager.UpdateInfo> infos = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
JSONObject o = updates.getJSONObject(i);
UpgradeManager.UpdateInfo
info = new UpgradeManager.UpdateInfo();
info.packageName = o.getString("pkg");
info.downloadUrl = o.getString("url");
infos.add(info);
}
// Post message
UpgradeManager.UpgradeInfo
ui = new UpgradeManager.UpgradeInfo();
ui.manifest = mf;
ui.updates = infos;
Message.obtain(mResponseHandler, 1, ui).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
private static class DownloadHandler extends Handler {
private UpgradeManager.OnUpgradeListener mListener;
public DownloadHandler(UpgradeManager.OnUpgradeListener listener) {
mListener = listener;
}
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
mListener.onUpgrade((Boolean) msg.obj);
break;
}
}
}
private UpgradeManager.DownloadHandler mHandler;
private void upgradeBundles(final UpgradeManager.UpgradeInfo info, final UpgradeManager.OnUpgradeListener listener) {
// Just for example, you can do this by OkHttp or something.
mHandler = new UpgradeManager.DownloadHandler(listener);
new Thread() {
@Override public void run() {
try {
// Update manifest
if (info.manifest != null) {
if (!Small.updateManifest(info.manifest, false)) {
Message.obtain(mHandler, 1, false).sendToTarget();
return;
}
}
// Download bundles
List<UpgradeManager.UpdateInfo> updates = info.updates;
for (UpgradeManager.UpdateInfo u : updates) {
// Get the patch file for downloading
net.wequick.small.Bundle bundle = Small.getBundle(u.packageName);
File file = bundle.getPatchFile();
// Download
URL url = new URL(u.downloadUrl);
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
InputStream is = urlConn.getInputStream();
OutputStream os = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
os.write(buffer, 0, length);
}
os.flush();
os.close();
is.close();
// Upgrade
bundle.upgrade();
}
Message.obtain(mHandler, 1, true).sendToTarget();
} catch (IOException e) {
e.printStackTrace();
Message.obtain(mHandler, 1, false).sendToTarget();
}
}
}.start();
}
}
复制代码
上面这个类就实现了热修复的功能 把bundles.json放在你的服务器上 这里的url换成你自己的url
然后调用
new UpgradeManager(getContext()).checkUpgrade();
就可以你的服务器下载最新的.so文件了
private void requestUpgradeInfo(Map versions, UpgradeManager.OnResponseListener listener) {
System.out.println(versions); // this should be passed as HTTP parameters
mResponseHandler = new UpgradeManager.ResponseHandler(listener);
new Thread() {
@Override public void run() {
try {
// Example HTTP request to get the upgrade bundles information.
// Json format see http://wequick.github.io/small/upgrade/bundles.json
URL url = new URL("yourUrl");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
StringBuilder sb = new StringBuilder();
InputStream is = conn.getInputStream();
byte[] buffer = new byte[1024];
int length;
while ((length = is.read(buffer)) != -1) {
sb.append(new String(buffer, 0, length));
}
// Parse json
JSONObject jo = new JSONObject(sb.toString());
JSONObject mf = jo.has("manifest") ? jo.getJSONObject("manifest") : null;
JSONArray updates = jo.getJSONArray("updates");
int N = updates.length();
List<UpgradeManager.UpdateInfo> infos = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
JSONObject o = updates.getJSONObject(i);
UpgradeManager.UpdateInfo
info = new UpgradeManager.UpdateInfo();
info.packageName = o.getString("pkg");
info.downloadUrl = o.getString("url");
infos.add(info);
}
// Post message
UpgradeManager.UpgradeInfo
ui = new UpgradeManager.UpgradeInfo();
ui.manifest = mf;
ui.updates = infos;
Message.obtain(mResponseHandler, 1, ui).sendToTarget();
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
复制代码
bundles.json的书写规则
{
"manifest": {
"version": "1.0.0",
"bundles": [
{
"uri": "lib.utils",
"pkg": "net.wequick.example.small.lib.utils"
},
{
"uri": "lib.style",
"pkg": "com.example.mysmall.lib.style"
},
{
"uri": "lib.analytics",
"pkg": "net.wequick.example.lib.analytics"
},
{
"uri": "main",
"pkg": "net.wequick.example.small.app.main"
},
{
"uri": "home",
"pkg": "net.wequick.example.small.app.home"
},
{
"uri": "mine",
"pkg": "net.wequick.example.small.app.mine"
},
{
"uri": "detail",
"pkg": "net.wequick.example.small.app.detail",
"rules": {
"sub": "Sub"
}
},
{
"uri": "stub",
"type": "app",
"pkg": "net.wequick.example.small.appok_if_stub"
},
{
"uri": "about",
"pkg": "net.wequick.example.small.app.about"
}
]
},
"updates": [
{
"pkg": "net.wequick.example.small.app.about",
"url": "http://wequick.github.io/small/upgrade/libnet_wequick_example_small_app_about.so"
},
{
"pkg": "net.wequick.example.small.lib.utils",
"url": "http://wequick.github.io/small/upgrade/libnet_wequick_example_small_lib_utils.so"
},
{
"pkg": "com.example.mysmall.lib.style",
"url": "http://wequick.github.io/small/upgrade/libcom_example_mysmall_lib_style.so"
},
{
"pkg": "net.wequick.example.small.app.home",
"url": "http://wequick.github.io/small/upgrade/libnet_wequick_example_small_app_home.so"
}
]
}
复制代码
看到这我们发现bundles的第一个标签是 manifest ,从上面代码发现当我们从服务器获取到bundles.json文件时 就去解析文件内容,解析到***manifest***标签的时候 ,开始修改***AndroidMainfes***文件,从而达到更新***AndroidMainfest*** 文件
再来看bundles.json文件 ***updates***标签 这里面 pkg 对应的是我们插件的包名 ***url***则对应的是我们服务器上对应的.So文件的地址,拿到.So文件的地址,就去下载并替换原有的.So文件,从而达到热修复的作用。
其实Small还不能说是热修复,因为当So文件被替换修改的时候需要退出应用,再次进去入才能有效果。