@capgo/capacitor-updater 3.2.0 → 3.2.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +207 -130
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleInfo.java +130 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/BundleStatus.java +36 -0
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdater.java +403 -288
- package/android/src/main/java/ee/forgr/capacitor_updater/CapacitorUpdaterPlugin.java +485 -268
- package/dist/docs.json +512 -109
- package/dist/esm/definitions.d.ts +201 -69
- package/dist/esm/web.d.ts +21 -16
- package/dist/esm/web.js +29 -23
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +29 -23
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +29 -23
- package/dist/plugin.js.map +1 -1
- package/ios/Plugin/BundleInfo.swift +94 -0
- package/ios/Plugin/BundleStatus.swift +41 -0
- package/ios/Plugin/CapacitorUpdater.swift +341 -88
- package/ios/Plugin/CapacitorUpdaterPlugin.m +4 -2
- package/ios/Plugin/CapacitorUpdaterPlugin.swift +277 -166
- package/ios/Plugin/ObjectPreferences.swift +97 -0
- package/package.json +2 -1
|
@@ -1,27 +1,20 @@
|
|
|
1
1
|
package ee.forgr.capacitor_updater;
|
|
2
2
|
|
|
3
|
-
import android.app.Activity;
|
|
4
|
-
import android.content.Context;
|
|
5
3
|
import android.content.SharedPreferences;
|
|
6
|
-
import android.content.pm.PackageInfo;
|
|
7
|
-
import android.content.pm.PackageManager;
|
|
8
|
-
import android.os.Build;
|
|
9
4
|
import android.util.Log;
|
|
10
5
|
|
|
11
|
-
import com.android.volley.AuthFailureError;
|
|
12
6
|
import com.android.volley.Request;
|
|
13
7
|
import com.android.volley.RequestQueue;
|
|
14
8
|
import com.android.volley.Response;
|
|
15
9
|
import com.android.volley.VolleyError;
|
|
16
|
-
import com.android.volley.toolbox.
|
|
17
|
-
import com.
|
|
10
|
+
import com.android.volley.toolbox.JsonObjectRequest;
|
|
11
|
+
import com.getcapacitor.plugin.WebView;
|
|
18
12
|
|
|
19
13
|
import org.json.JSONException;
|
|
20
14
|
import org.json.JSONObject;
|
|
21
15
|
|
|
22
16
|
import java.io.BufferedInputStream;
|
|
23
17
|
import java.io.DataInputStream;
|
|
24
|
-
import java.io.DataOutputStream;
|
|
25
18
|
import java.io.File;
|
|
26
19
|
import java.io.FileInputStream;
|
|
27
20
|
import java.io.FileNotFoundException;
|
|
@@ -29,387 +22,509 @@ import java.io.FileOutputStream;
|
|
|
29
22
|
import java.io.FilenameFilter;
|
|
30
23
|
import java.io.IOException;
|
|
31
24
|
import java.io.InputStream;
|
|
32
|
-
import java.net.HttpURLConnection;
|
|
33
25
|
import java.net.URL;
|
|
34
26
|
import java.net.URLConnection;
|
|
35
27
|
import java.security.SecureRandom;
|
|
36
|
-
import java.util.
|
|
37
|
-
import java.util.
|
|
28
|
+
import java.util.ArrayList;
|
|
29
|
+
import java.util.Date;
|
|
30
|
+
import java.util.List;
|
|
38
31
|
import java.util.zip.ZipEntry;
|
|
39
32
|
import java.util.zip.ZipInputStream;
|
|
40
|
-
import java.util.ArrayList;
|
|
41
|
-
import android.provider.Settings.Secure;
|
|
42
33
|
|
|
43
34
|
interface Callback {
|
|
44
35
|
void callback(JSONObject jsonObject);
|
|
45
36
|
}
|
|
46
37
|
|
|
47
38
|
public class CapacitorUpdater {
|
|
39
|
+
private static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
40
|
+
private static final SecureRandom rnd = new SecureRandom();
|
|
41
|
+
|
|
42
|
+
private static final String INFO_SUFFIX = "_info";
|
|
43
|
+
|
|
44
|
+
private static final String FALLBACK_VERSION = "pastVersion";
|
|
45
|
+
private static final String NEXT_VERSION = "nextVersion";
|
|
46
|
+
private static final String bundleDirectory = "versions";
|
|
47
|
+
|
|
48
|
+
public static final String TAG = "Capacitor-updater";
|
|
49
|
+
public static final String pluginVersion = "3.2.1-alpha.0";
|
|
50
|
+
|
|
51
|
+
public SharedPreferences.Editor editor;
|
|
52
|
+
public SharedPreferences prefs;
|
|
53
|
+
|
|
54
|
+
public RequestQueue requestQueue;
|
|
55
|
+
|
|
56
|
+
public File documentsDir;
|
|
57
|
+
public String versionBuild = "";
|
|
58
|
+
public String versionCode = "";
|
|
59
|
+
public String versionOs = "";
|
|
60
|
+
|
|
48
61
|
public String statsUrl = "";
|
|
49
62
|
public String appId = "";
|
|
50
63
|
public String deviceID = "";
|
|
51
|
-
private String pluginVersion = "3.2.0";
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
private FilenameFilter filter = new FilenameFilter() {
|
|
65
|
+
private final FilenameFilter filter = new FilenameFilter() {
|
|
55
66
|
@Override
|
|
56
|
-
public boolean accept(File f, String name) {
|
|
67
|
+
public boolean accept(final File f, final String name) {
|
|
57
68
|
// ignore directories generated by mac os x
|
|
58
69
|
return !name.startsWith("__MACOSX") && !name.startsWith(".") && !name.startsWith(".DS_Store");
|
|
59
70
|
}
|
|
60
71
|
};
|
|
61
|
-
|
|
62
|
-
private
|
|
63
|
-
private String versionCode = "";
|
|
64
|
-
private String versionOs = "";
|
|
65
|
-
private String TAG = "Capacitor-updater";
|
|
66
|
-
private Context context;
|
|
67
|
-
private String basePathHot = "versions";
|
|
68
|
-
private SharedPreferences prefs;
|
|
69
|
-
private SharedPreferences.Editor editor;
|
|
70
|
-
|
|
71
|
-
static final String AB = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
72
|
-
static SecureRandom rnd = new SecureRandom();
|
|
73
|
-
|
|
74
|
-
private int calcTotalPercent(int percent, int min, int max) {
|
|
72
|
+
|
|
73
|
+
private int calcTotalPercent(final int percent, final int min, final int max) {
|
|
75
74
|
return (percent * (max - min)) / 100 + min;
|
|
76
75
|
}
|
|
77
76
|
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
void notifyDownload(final String id, final int percent) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
private String randomString(final int len){
|
|
82
|
+
final StringBuilder sb = new StringBuilder(len);
|
|
80
83
|
for(int i = 0; i < len; i++)
|
|
81
84
|
sb.append(AB.charAt(rnd.nextInt(AB.length())));
|
|
82
85
|
return sb.toString();
|
|
83
86
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.editor = prefs.edit();
|
|
89
|
-
this.versionOs = Build.VERSION.RELEASE;
|
|
90
|
-
this.deviceID = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
|
|
91
|
-
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
|
92
|
-
this.versionBuild = pInfo.versionName;
|
|
93
|
-
this.versionCode = Integer.toString(pInfo.versionCode);
|
|
94
|
-
}
|
|
95
|
-
public CapacitorUpdater (Context context, CapacitorUpdaterPlugin plugin) throws PackageManager.NameNotFoundException {
|
|
96
|
-
this.context = context;
|
|
97
|
-
this.plugin = plugin;
|
|
98
|
-
this.prefs = context.getSharedPreferences("CapWebViewSettings", Activity.MODE_PRIVATE);
|
|
99
|
-
this.editor = prefs.edit();
|
|
100
|
-
this.versionOs = Build.VERSION.RELEASE;
|
|
101
|
-
this.deviceID = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
|
|
102
|
-
PackageInfo pInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
|
|
103
|
-
this.versionBuild = pInfo.versionName;
|
|
104
|
-
this.versionCode = Integer.toString(pInfo.versionCode);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
private Boolean unzip(String source, String dest) {
|
|
108
|
-
File zipFile = new File(this.context.getFilesDir() + "/" + source);
|
|
109
|
-
File targetDirectory = new File(this.context.getFilesDir() + "/" + dest);
|
|
110
|
-
ZipInputStream zis = null;
|
|
111
|
-
try {
|
|
112
|
-
zis = new ZipInputStream(
|
|
113
|
-
new BufferedInputStream(new FileInputStream(zipFile)));
|
|
114
|
-
} catch (FileNotFoundException e) {
|
|
115
|
-
e.printStackTrace();
|
|
116
|
-
return false;
|
|
117
|
-
}
|
|
87
|
+
|
|
88
|
+
private File unzip(final String id, final File zipFile, final String dest) throws IOException {
|
|
89
|
+
final File targetDirectory = new File(this.documentsDir, dest);
|
|
90
|
+
final ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(zipFile)));
|
|
118
91
|
try {
|
|
119
|
-
ZipEntry ze;
|
|
120
92
|
int count;
|
|
121
|
-
int
|
|
122
|
-
byte[] buffer = new byte[
|
|
123
|
-
long
|
|
124
|
-
long
|
|
93
|
+
final int bufferSize = 8192;
|
|
94
|
+
final byte[] buffer = new byte[bufferSize];
|
|
95
|
+
final long lengthTotal = zipFile.length();
|
|
96
|
+
long lengthRead = bufferSize;
|
|
125
97
|
int percent = 0;
|
|
126
|
-
this.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
98
|
+
this.notifyDownload(id, 75);
|
|
99
|
+
|
|
100
|
+
ZipEntry entry;
|
|
101
|
+
while ((entry = zis.getNextEntry()) != null) {
|
|
102
|
+
final File file = new File(targetDirectory, entry.getName());
|
|
103
|
+
final String canonicalPath = file.getCanonicalPath();
|
|
104
|
+
final String canonicalDir = (new File(String.valueOf(targetDirectory))).getCanonicalPath();
|
|
105
|
+
final File dir = entry.isDirectory() ? file : file.getParentFile();
|
|
106
|
+
|
|
132
107
|
if (!canonicalPath.startsWith(canonicalDir)) {
|
|
133
108
|
throw new FileNotFoundException("SecurityException, Failed to ensure directory is the start path : " +
|
|
134
109
|
canonicalDir + " of " + canonicalPath);
|
|
135
110
|
}
|
|
136
|
-
|
|
111
|
+
|
|
112
|
+
if (!dir.isDirectory() && !dir.mkdirs()) {
|
|
137
113
|
throw new FileNotFoundException("Failed to ensure directory: " +
|
|
138
114
|
dir.getAbsolutePath());
|
|
139
|
-
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (entry.isDirectory()) {
|
|
140
118
|
continue;
|
|
141
|
-
|
|
142
|
-
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
try(final FileOutputStream outputStream = new FileOutputStream(file)) {
|
|
143
122
|
while ((count = zis.read(buffer)) != -1)
|
|
144
|
-
|
|
145
|
-
} finally {
|
|
146
|
-
fileOut.close();
|
|
123
|
+
outputStream.write(buffer, 0, count);
|
|
147
124
|
}
|
|
148
|
-
|
|
149
|
-
|
|
125
|
+
|
|
126
|
+
final int newPercent = (int)((lengthRead * 100) / lengthTotal);
|
|
127
|
+
if (lengthTotal > 1 && newPercent != percent) {
|
|
150
128
|
percent = newPercent;
|
|
151
|
-
this.
|
|
129
|
+
this.notifyDownload(id, this.calcTotalPercent(percent, 75, 90));
|
|
152
130
|
}
|
|
153
|
-
|
|
131
|
+
|
|
132
|
+
lengthRead += entry.getCompressedSize();
|
|
154
133
|
}
|
|
155
|
-
|
|
156
|
-
Log.i(TAG, "unzip error", e);
|
|
157
|
-
return false;
|
|
134
|
+
return targetDirectory;
|
|
158
135
|
} finally {
|
|
159
136
|
try {
|
|
160
137
|
zis.close();
|
|
161
|
-
} catch (IOException e) {
|
|
162
|
-
e
|
|
163
|
-
return false;
|
|
138
|
+
} catch (final IOException e) {
|
|
139
|
+
Log.e(TAG, "Failed to close zip input stream", e);
|
|
164
140
|
}
|
|
165
|
-
return true;
|
|
166
141
|
}
|
|
167
142
|
}
|
|
168
143
|
|
|
169
|
-
private
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return false;
|
|
144
|
+
private void flattenAssets(final File sourceFile, final String dest) throws IOException {
|
|
145
|
+
if (!sourceFile.exists()) {
|
|
146
|
+
throw new FileNotFoundException("Source file not found: " + sourceFile.getPath());
|
|
173
147
|
}
|
|
174
|
-
File
|
|
175
|
-
|
|
176
|
-
String[]
|
|
177
|
-
if (
|
|
178
|
-
|
|
148
|
+
final File destinationFile = new File(this.documentsDir, dest);
|
|
149
|
+
destinationFile.getParentFile().mkdirs();
|
|
150
|
+
final String[] entries = sourceFile.list(this.filter);
|
|
151
|
+
if (entries == null || entries.length == 0) {
|
|
152
|
+
throw new IOException("Source file was not a directory or was empty: " + sourceFile.getPath());
|
|
179
153
|
}
|
|
180
|
-
if (
|
|
181
|
-
File
|
|
182
|
-
|
|
154
|
+
if (entries.length == 1 && !"index.html".equals(entries[0])) {
|
|
155
|
+
final File child = new File(sourceFile, entries[0]);
|
|
156
|
+
child.renameTo(destinationFile);
|
|
183
157
|
} else {
|
|
184
|
-
|
|
158
|
+
sourceFile.renameTo(destinationFile);
|
|
185
159
|
}
|
|
186
|
-
|
|
187
|
-
return true;
|
|
160
|
+
sourceFile.delete();
|
|
188
161
|
}
|
|
189
162
|
|
|
190
|
-
private
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
163
|
+
private File downloadFile(final String id, final String url, final String dest) throws IOException {
|
|
164
|
+
|
|
165
|
+
final URL u = new URL(url);
|
|
166
|
+
final URLConnection connection = u.openConnection();
|
|
167
|
+
final InputStream is = u.openStream();
|
|
168
|
+
final DataInputStream dis = new DataInputStream(is);
|
|
169
|
+
|
|
170
|
+
final File target = new File(this.documentsDir, dest);
|
|
171
|
+
target.getParentFile().mkdirs();
|
|
172
|
+
target.createNewFile();
|
|
173
|
+
final FileOutputStream fos = new FileOutputStream(target);
|
|
174
|
+
|
|
175
|
+
final long totalLength = connection.getContentLength();
|
|
176
|
+
final int bufferSize = 1024;
|
|
177
|
+
final byte[] buffer = new byte[bufferSize];
|
|
178
|
+
int length;
|
|
179
|
+
|
|
180
|
+
int bytesRead = bufferSize;
|
|
181
|
+
int percent = 0;
|
|
182
|
+
this.notifyDownload(id, 10);
|
|
183
|
+
while ((length = dis.read(buffer))>0) {
|
|
184
|
+
fos.write(buffer, 0, length);
|
|
185
|
+
final int newPercent = (int)((bytesRead * 100) / totalLength);
|
|
186
|
+
if (totalLength > 1 && newPercent != percent) {
|
|
187
|
+
percent = newPercent;
|
|
188
|
+
this.notifyDownload(id, this.calcTotalPercent(percent, 10, 70));
|
|
215
189
|
}
|
|
216
|
-
|
|
217
|
-
Log.e(TAG, "downloadFile error", e);
|
|
218
|
-
return false;
|
|
190
|
+
bytesRead += length;
|
|
219
191
|
}
|
|
220
|
-
return
|
|
192
|
+
return target;
|
|
221
193
|
}
|
|
222
194
|
|
|
223
|
-
private void deleteDirectory(File file) throws IOException {
|
|
195
|
+
private void deleteDirectory(final File file) throws IOException {
|
|
224
196
|
if (file.isDirectory()) {
|
|
225
|
-
File[] entries = file.listFiles();
|
|
197
|
+
final File[] entries = file.listFiles();
|
|
226
198
|
if (entries != null) {
|
|
227
|
-
for (File entry : entries) {
|
|
228
|
-
deleteDirectory(entry);
|
|
199
|
+
for (final File entry : entries) {
|
|
200
|
+
this.deleteDirectory(entry);
|
|
229
201
|
}
|
|
230
202
|
}
|
|
231
203
|
}
|
|
232
204
|
if (!file.delete()) {
|
|
233
|
-
throw new IOException("Failed to delete " + file);
|
|
205
|
+
throw new IOException("Failed to delete: " + file);
|
|
234
206
|
}
|
|
235
207
|
}
|
|
236
208
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
209
|
+
private void setCurrentBundle(final File bundle) {
|
|
210
|
+
this.editor.putString(WebView.CAP_SERVER_PATH, bundle.getPath());
|
|
211
|
+
Log.i(TAG, "Current bundle set to: " + bundle);
|
|
212
|
+
this.editor.commit();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
public BundleInfo download(final String url, final String version) throws IOException {
|
|
216
|
+
final String id = this.randomString(10);
|
|
217
|
+
this.saveBundleInfo(id, new BundleInfo(id, version, BundleStatus.DOWNLOADING, new Date(System.currentTimeMillis())));
|
|
218
|
+
this.notifyDownload(id, 0);
|
|
219
|
+
final String idName = bundleDirectory + "/" + id;
|
|
220
|
+
this.notifyDownload(id, 5);
|
|
221
|
+
final File downloaded = this.downloadFile(id, url, this.randomString(10));
|
|
222
|
+
this.notifyDownload(id, 71);
|
|
223
|
+
final File unzipped = this.unzip(id, downloaded, this.randomString(10));
|
|
224
|
+
downloaded.delete();
|
|
225
|
+
this.notifyDownload(id, 91);
|
|
226
|
+
this.flattenAssets(unzipped, idName);
|
|
227
|
+
this.notifyDownload(id, 100);
|
|
228
|
+
this.saveBundleInfo(id, null);
|
|
229
|
+
BundleInfo info = new BundleInfo(id, version, BundleStatus.PENDING, new Date(System.currentTimeMillis()));
|
|
230
|
+
this.saveBundleInfo(id, info);
|
|
231
|
+
return info;
|
|
261
232
|
}
|
|
262
233
|
|
|
263
|
-
public
|
|
264
|
-
|
|
265
|
-
File destHot = new File(this.
|
|
266
|
-
Log.
|
|
234
|
+
public List<BundleInfo> list() {
|
|
235
|
+
final List<BundleInfo> res = new ArrayList<>();
|
|
236
|
+
final File destHot = new File(this.documentsDir, bundleDirectory);
|
|
237
|
+
Log.d(TAG, "list File : " + destHot.getPath());
|
|
267
238
|
if (destHot.exists()) {
|
|
268
|
-
for (File i : destHot.listFiles()) {
|
|
269
|
-
|
|
239
|
+
for (final File i : destHot.listFiles()) {
|
|
240
|
+
final String id = i.getName();
|
|
241
|
+
res.add(this.getBundleInfo(id));
|
|
270
242
|
}
|
|
271
243
|
} else {
|
|
272
|
-
Log.i(TAG, "No
|
|
244
|
+
Log.i(TAG, "No versions available to list" + destHot);
|
|
273
245
|
}
|
|
274
246
|
return res;
|
|
275
247
|
}
|
|
276
248
|
|
|
277
|
-
public Boolean delete(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
249
|
+
public Boolean delete(final String id) throws IOException {
|
|
250
|
+
final BundleInfo deleted = this.getBundleInfo(id);
|
|
251
|
+
final File bundle = new File(this.documentsDir, bundleDirectory + "/" + id);
|
|
252
|
+
if (bundle.exists()) {
|
|
253
|
+
this.deleteDirectory(bundle);
|
|
254
|
+
this.removeBundleInfo(id);
|
|
281
255
|
return true;
|
|
282
256
|
}
|
|
283
|
-
Log.
|
|
284
|
-
this.sendStats("delete",
|
|
257
|
+
Log.e(TAG, "Directory not removed: " + bundle.getPath());
|
|
258
|
+
this.sendStats("delete", deleted);
|
|
285
259
|
return false;
|
|
286
260
|
}
|
|
287
261
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
262
|
+
private File getBundleDirectory(final String id) {
|
|
263
|
+
return new File(this.documentsDir, bundleDirectory + "/" + id);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
private boolean bundleExists(final File bundle) {
|
|
267
|
+
if(bundle == null || !bundle.exists()) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return new File(bundle.getPath(), "/index.html").exists();
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
public Boolean set(final BundleInfo bundle) {
|
|
275
|
+
return this.set(bundle.getId());
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
public Boolean set(final String id) {
|
|
279
|
+
|
|
280
|
+
final BundleInfo existing = this.getBundleInfo(id);
|
|
281
|
+
final File bundle = this.getBundleDirectory(id);
|
|
282
|
+
|
|
283
|
+
Log.i(TAG, "Setting next active bundle: " + existing);
|
|
284
|
+
if (this.bundleExists(bundle)) {
|
|
285
|
+
this.setCurrentBundle(bundle);
|
|
286
|
+
this.setBundleStatus(id, BundleStatus.PENDING);
|
|
287
|
+
this.sendStats("set", existing);
|
|
297
288
|
return true;
|
|
298
289
|
}
|
|
299
|
-
sendStats("set_fail",
|
|
290
|
+
this.sendStats("set_fail", existing);
|
|
300
291
|
return false;
|
|
301
292
|
}
|
|
302
293
|
|
|
303
|
-
public void
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
String versionBuild = this.versionBuild;
|
|
307
|
-
String versionCode = this.versionCode;
|
|
308
|
-
String versionOs = this.versionOs;
|
|
309
|
-
String pluginVersion = this.pluginVersion;
|
|
310
|
-
String versionName = getVersionName().equals("") ? "builtin" : getVersionName();
|
|
311
|
-
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
|
|
312
|
-
new Response.Listener<String>() {
|
|
313
|
-
@Override
|
|
314
|
-
public void onResponse(String response) {
|
|
315
|
-
try {
|
|
316
|
-
JSONObject jsonObject = new JSONObject(response);
|
|
317
|
-
callback.callback(jsonObject);
|
|
318
|
-
} catch (JSONException e) {
|
|
319
|
-
e.printStackTrace();
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
}, new Response.ErrorListener() {
|
|
323
|
-
@Override
|
|
324
|
-
public void onErrorResponse(VolleyError error) {
|
|
325
|
-
Log.e(TAG, "Error getting Latest" + error);
|
|
326
|
-
}
|
|
327
|
-
}) {
|
|
328
|
-
@Override
|
|
329
|
-
public Map<String, String> getHeaders() throws AuthFailureError {
|
|
330
|
-
Map<String, String> params = new HashMap<String, String>();
|
|
331
|
-
params.put("cap_platform", "android");
|
|
332
|
-
params.put("cap_device_id", deviceID);
|
|
333
|
-
params.put("cap_app_id", appId);
|
|
334
|
-
params.put("cap_version_build", versionBuild);
|
|
335
|
-
params.put("cap_version_code", versionCode);
|
|
336
|
-
params.put("cap_version_os", versionOs);
|
|
337
|
-
params.put("cap_version_name", versionName);
|
|
338
|
-
params.put("cap_plugin_version", pluginVersion);
|
|
339
|
-
return params;
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
RequestQueue requestQueue = Volley.newRequestQueue(this.context);
|
|
343
|
-
requestQueue.add(stringRequest);
|
|
294
|
+
public void commit(final BundleInfo bundle) {
|
|
295
|
+
this.setBundleStatus(bundle.getId(), BundleStatus.SUCCESS);
|
|
296
|
+
this.setFallbackVersion(bundle);
|
|
344
297
|
}
|
|
345
298
|
|
|
346
|
-
public
|
|
347
|
-
|
|
299
|
+
public void reset() {
|
|
300
|
+
this.reset(false);
|
|
348
301
|
}
|
|
349
302
|
|
|
350
|
-
public
|
|
351
|
-
|
|
303
|
+
public void rollback(final BundleInfo bundle) {
|
|
304
|
+
this.setBundleStatus(bundle.getId(), BundleStatus.ERROR);
|
|
352
305
|
}
|
|
353
306
|
|
|
354
|
-
public void reset() {
|
|
355
|
-
|
|
356
|
-
this.
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
public void
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
String
|
|
307
|
+
public void reset(final boolean internal) {
|
|
308
|
+
this.setCurrentBundle(new File("public"));
|
|
309
|
+
this.setFallbackVersion(null);
|
|
310
|
+
this.setNextVersion(null);
|
|
311
|
+
if(!internal) {
|
|
312
|
+
this.sendStats("reset", this.getCurrentBundle());
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
public void getLatest(final String updateUrl, final Callback callback) {
|
|
317
|
+
final String deviceID = this.deviceID;
|
|
318
|
+
final String appId = this.appId;
|
|
319
|
+
final String versionBuild = this.versionBuild;
|
|
320
|
+
final String versionCode = this.versionCode;
|
|
321
|
+
final String versionOs = this.versionOs;
|
|
322
|
+
final String pluginVersion = CapacitorUpdater.pluginVersion;
|
|
323
|
+
final String version = this.getCurrentBundle().getId();
|
|
368
324
|
try {
|
|
369
|
-
|
|
325
|
+
JSONObject json = new JSONObject();
|
|
370
326
|
json.put("platform", "android");
|
|
371
|
-
json.put("
|
|
327
|
+
json.put("device_id", deviceID);
|
|
328
|
+
json.put("app_id", appId);
|
|
329
|
+
json.put("version_build", versionBuild);
|
|
330
|
+
json.put("version_code", versionCode);
|
|
331
|
+
json.put("version_os", versionOs);
|
|
372
332
|
json.put("version_name", version);
|
|
333
|
+
json.put("plugin_version", pluginVersion);
|
|
334
|
+
|
|
335
|
+
// Building a request
|
|
336
|
+
JsonObjectRequest request = new JsonObjectRequest(
|
|
337
|
+
Request.Method.POST,
|
|
338
|
+
updateUrl,
|
|
339
|
+
json,
|
|
340
|
+
new Response.Listener<JSONObject>() {
|
|
341
|
+
@Override
|
|
342
|
+
public void onResponse(JSONObject response) {
|
|
343
|
+
callback.callback(response);
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
new Response.ErrorListener(){
|
|
347
|
+
@Override
|
|
348
|
+
public void onErrorResponse(VolleyError error) {
|
|
349
|
+
Log.e(TAG, "Error getting Latest " + error);
|
|
350
|
+
}
|
|
351
|
+
});
|
|
352
|
+
this.requestQueue.add(request);
|
|
353
|
+
} catch(JSONException ex){
|
|
354
|
+
// Catch if something went wrong with the params
|
|
355
|
+
Log.e(TAG, "Error getLatest JSONException " + ex);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
public void sendStats(final String action, final BundleInfo bundle) {
|
|
360
|
+
String statsUrl = this.statsUrl;
|
|
361
|
+
if (statsUrl == null || "".equals(statsUrl) || statsUrl.length() == 0) { return; }
|
|
362
|
+
try {
|
|
363
|
+
JSONObject json = new JSONObject();
|
|
364
|
+
json.put("platform", "android");
|
|
373
365
|
json.put("device_id", this.deviceID);
|
|
366
|
+
json.put("app_id", this.appId);
|
|
374
367
|
json.put("version_build", this.versionBuild);
|
|
375
368
|
json.put("version_code", this.versionCode);
|
|
376
369
|
json.put("version_os", this.versionOs);
|
|
377
|
-
json.put("
|
|
378
|
-
json.put("
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
370
|
+
json.put("version_name", bundle.getVersionName());
|
|
371
|
+
json.put("plugin_version", pluginVersion);
|
|
372
|
+
json.put("action", action);
|
|
373
|
+
|
|
374
|
+
// Building a request
|
|
375
|
+
JsonObjectRequest request = new JsonObjectRequest(
|
|
376
|
+
Request.Method.POST,
|
|
377
|
+
statsUrl,
|
|
378
|
+
json,
|
|
379
|
+
new Response.Listener<JSONObject>() {
|
|
380
|
+
@Override
|
|
381
|
+
public void onResponse(JSONObject response) {
|
|
382
|
+
Log.i(TAG, "Stats send for \"" + action + "\", version " + bundle.getVersionName());
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
new Response.ErrorListener(){
|
|
386
|
+
@Override
|
|
387
|
+
public void onErrorResponse(VolleyError error) {
|
|
388
|
+
Log.i(TAG, "Stats send for \"" + action + "\", version " + bundle.getVersionName());
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
this.requestQueue.add(request);
|
|
392
|
+
} catch(JSONException ex){
|
|
393
|
+
// Catch if something went wrong with the params
|
|
394
|
+
Log.e(TAG, "Error sendStats JSONException " + ex);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
public BundleInfo getBundleInfo(String id) {
|
|
399
|
+
if(id == null) {
|
|
400
|
+
id = BundleInfo.VERSION_UNKNOWN;
|
|
401
|
+
}
|
|
402
|
+
Log.d(TAG, "Getting info for bundle [" + id + "]");
|
|
403
|
+
BundleInfo result;
|
|
404
|
+
if(BundleInfo.ID_BUILTIN.equals(id)) {
|
|
405
|
+
result = new BundleInfo(id, (String) null, BundleStatus.SUCCESS, "");
|
|
406
|
+
} else {
|
|
407
|
+
try {
|
|
408
|
+
String stored = this.prefs.getString(id + INFO_SUFFIX, "");
|
|
409
|
+
result = BundleInfo.fromJSON(stored);
|
|
410
|
+
} catch (JSONException e) {
|
|
411
|
+
Log.e(TAG, "Failed to parse info for bundle [" + id + "] ", e);
|
|
412
|
+
result = new BundleInfo(id, (String) null, BundleStatus.PENDING, "");
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
Log.d(TAG, "Returning info [" + id + "] " + result);
|
|
417
|
+
return result;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
public BundleInfo getBundleInfoByName(final String versionName) {
|
|
421
|
+
final List<BundleInfo> installed = this.list();
|
|
422
|
+
for(final BundleInfo i : installed) {
|
|
423
|
+
if(i.getVersionName().equals(versionName)) {
|
|
424
|
+
return i;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private void removeBundleInfo(final String id) {
|
|
431
|
+
this.saveBundleInfo(id, null);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private void saveBundleInfo(final String id, final BundleInfo info) {
|
|
435
|
+
if(id == null || (info != null && (info.isBuiltin() || info.isUnknown()))) {
|
|
436
|
+
Log.d(TAG, "Not saving info for bundle: [" + id + "] " + info);
|
|
382
437
|
return;
|
|
383
438
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
439
|
+
|
|
440
|
+
if(info == null) {
|
|
441
|
+
Log.d(TAG, "Removing info for bundle [" + id + "]");
|
|
442
|
+
this.editor.remove(id + INFO_SUFFIX);
|
|
443
|
+
} else {
|
|
444
|
+
final BundleInfo update = info.setId(id);
|
|
445
|
+
Log.d(TAG, "Storing info for bundle [" + id + "] " + update.toString());
|
|
446
|
+
this.editor.putString(id + INFO_SUFFIX, update.toString());
|
|
447
|
+
}
|
|
448
|
+
this.editor.commit();
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
public void setVersionName(final String id, final String name) {
|
|
452
|
+
if(id != null) {
|
|
453
|
+
Log.d(TAG, "Setting name for bundle [" + id + "] to " + name);
|
|
454
|
+
BundleInfo info = this.getBundleInfo(id);
|
|
455
|
+
this.saveBundleInfo(id, info.setVersionName(name));
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private void setBundleStatus(final String id, final BundleStatus status) {
|
|
460
|
+
if(id != null && status != null) {
|
|
461
|
+
BundleInfo info = this.getBundleInfo(id);
|
|
462
|
+
Log.d(TAG, "Setting status for bundle [" + id + "] to " + status);
|
|
463
|
+
this.saveBundleInfo(id, info.setStatus(status));
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
private String getCurrentBundleId() {
|
|
468
|
+
if(this.isUsingBuiltin()) {
|
|
469
|
+
return BundleInfo.ID_BUILTIN;
|
|
470
|
+
} else {
|
|
471
|
+
final String path = this.getCurrentBundlePath();
|
|
472
|
+
return path.substring(path.lastIndexOf('/') + 1);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
public BundleInfo getCurrentBundle() {
|
|
477
|
+
return this.getBundleInfo(this.getCurrentBundleId());
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
public String getCurrentBundlePath() {
|
|
481
|
+
String path = this.prefs.getString(WebView.CAP_SERVER_PATH, "public");
|
|
482
|
+
if("".equals(path.trim())) {
|
|
483
|
+
return "public";
|
|
484
|
+
}
|
|
485
|
+
return path;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
public Boolean isUsingBuiltin() {
|
|
489
|
+
return this.getCurrentBundlePath().equals("public");
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
public BundleInfo getFallbackVersion() {
|
|
493
|
+
final String id = this.prefs.getString(FALLBACK_VERSION, BundleInfo.ID_BUILTIN);
|
|
494
|
+
return this.getBundleInfo(id);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
private void setFallbackVersion(final BundleInfo fallback) {
|
|
498
|
+
this.editor.putString(FALLBACK_VERSION,
|
|
499
|
+
fallback == null
|
|
500
|
+
? BundleInfo.ID_BUILTIN
|
|
501
|
+
: fallback.getId()
|
|
502
|
+
);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
public BundleInfo getNextVersion() {
|
|
506
|
+
final String id = this.prefs.getString(NEXT_VERSION, "");
|
|
507
|
+
if(id != "") {
|
|
508
|
+
return this.getBundleInfo(id);
|
|
509
|
+
} else {
|
|
510
|
+
return null;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
public boolean setNextVersion(final String next) {
|
|
515
|
+
if (next == null) {
|
|
516
|
+
this.editor.remove(NEXT_VERSION);
|
|
517
|
+
} else {
|
|
518
|
+
final File bundle = this.getBundleDirectory(next);
|
|
519
|
+
if (!this.bundleExists(bundle)) {
|
|
520
|
+
return false;
|
|
412
521
|
}
|
|
413
|
-
|
|
522
|
+
|
|
523
|
+
this.editor.putString(NEXT_VERSION, next);
|
|
524
|
+
this.setBundleStatus(next, BundleStatus.PENDING);
|
|
525
|
+
}
|
|
526
|
+
this.editor.commit();
|
|
527
|
+
return true;
|
|
414
528
|
}
|
|
529
|
+
|
|
415
530
|
}
|