Small插件化

Small 插件化

small1

跳转指定的activity

small2

先buildlib后buildBundle

small3

small也可以实现热修复的功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
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

然后调用

UpgradeManager(getContext()).checkUpgrade();```就可以你的服务器下载最新的.so文件了
1
2

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();

}

1
2
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文件被替换修改的时候需要推出应用,再次进去入才能有效果。