mirror of
https://gitcode.com/gh_mirrors/re/react-native-pushy.git
synced 2025-09-18 02:16:11 +08:00
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
451e298ba5 | ||
![]() |
1b5c07be9e | ||
![]() |
13cf53974e | ||
![]() |
2a1915c50c | ||
![]() |
3de78a9dbd | ||
![]() |
ef065e4072 | ||
![]() |
ff67829a27 |
@@ -8,7 +8,7 @@
|
||||
|
||||
### 优势
|
||||
|
||||
1. 基于阿里云高速 CDN 分发,对比其他在服务器在国外的热更新服务,分发更稳定,更新成功率极高。
|
||||
1. 基于阿里云高速 CDN 分发,对比其他服务器在国外的热更新服务,分发更稳定,更新成功率极高。
|
||||
2. 基于 bsdiff/hdiff 算法创建的**超小更新包**,通常版本迭代后在 1-10KB 之间,避免数百 KB 的流量消耗。
|
||||
3. 跨越多个版本进行更新时,只需要下载**一个更新包**,不需要逐版本依次更新。
|
||||
4. 命令行工具&网页双端管理,版本发布过程简单便捷,完全可以集成 CI。
|
||||
|
@@ -19,15 +19,13 @@ import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.HashMap;
|
||||
|
||||
import okio.BufferedSink;
|
||||
@@ -138,19 +136,6 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
|
||||
private static native byte[] hdiffPatch(byte[] origin, byte[] patch);
|
||||
|
||||
private void unzipToFile(ZipInputStream zis, File fmd) throws IOException {
|
||||
int count;
|
||||
|
||||
FileOutputStream fout = new FileOutputStream(fmd);
|
||||
|
||||
while ((count = zis.read(buffer)) != -1)
|
||||
{
|
||||
fout.write(buffer, 0, count);
|
||||
}
|
||||
|
||||
fout.close();
|
||||
zis.closeEntry();
|
||||
}
|
||||
|
||||
private void copyFile(File from, File fmd) throws IOException {
|
||||
int count;
|
||||
@@ -167,7 +152,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
in.close();
|
||||
}
|
||||
|
||||
private byte[] readBytes(ZipInputStream zis) throws IOException {
|
||||
private byte[] readBytes(InputStream zis) throws IOException {
|
||||
int count;
|
||||
|
||||
ByteArrayOutputStream fout = new ByteArrayOutputStream();
|
||||
@@ -177,7 +162,7 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
}
|
||||
|
||||
fout.close();
|
||||
zis.closeEntry();
|
||||
zis.close();
|
||||
return fout.toByteArray();
|
||||
}
|
||||
|
||||
@@ -246,15 +231,14 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
private void doFullPatch(DownloadTaskParams param) throws IOException {
|
||||
downloadFile(param);
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
|
||||
ZipEntry ze;
|
||||
String filename;
|
||||
|
||||
removeDirectory(param.unzipDirectory);
|
||||
param.unzipDirectory.mkdirs();
|
||||
|
||||
while ((ze = zis.getNextEntry()) != null)
|
||||
{
|
||||
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry ze = entries.nextElement();
|
||||
|
||||
String fn = ze.getName();
|
||||
File fmd = new File(param.unzipDirectory, fn);
|
||||
|
||||
@@ -267,10 +251,11 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
unzipToFile(zis, fmd);
|
||||
zipFile.unzipToFile(ze, fmd);
|
||||
}
|
||||
|
||||
zis.close();
|
||||
zipFile.close();
|
||||
|
||||
|
||||
if (UpdateContext.DEBUG) {
|
||||
Log.d("RNUpdate", "Unzip finished");
|
||||
@@ -278,9 +263,11 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
}
|
||||
|
||||
private void copyFromResource(HashMap<String, ArrayList<File> > resToCopy) throws IOException {
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(context.getPackageResourcePath())));
|
||||
ZipEntry ze;
|
||||
while ((ze = zis.getNextEntry()) != null) {
|
||||
SafeZipFile zipFile = new SafeZipFile(new File(context.getPackageResourcePath()));
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry ze = entries.nextElement();
|
||||
|
||||
String fn = ze.getName();
|
||||
ArrayList<File> targets = resToCopy.get(fn);
|
||||
if (targets != null) {
|
||||
@@ -292,37 +279,35 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
if (lastTarget != null) {
|
||||
copyFile(lastTarget, target);
|
||||
} else {
|
||||
unzipToFile(zis, target);
|
||||
zipFile.unzipToFile(ze, target);
|
||||
lastTarget = target;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
zipFile.close();
|
||||
}
|
||||
|
||||
private void doPatchFromApk(DownloadTaskParams param) throws IOException, JSONException {
|
||||
downloadFile(param);
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
|
||||
ZipEntry ze;
|
||||
int count;
|
||||
String filename;
|
||||
removeDirectory(param.unzipDirectory);
|
||||
param.unzipDirectory.mkdirs();
|
||||
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
||||
|
||||
boolean foundDiff = false;
|
||||
boolean foundBundlePatch = false;
|
||||
|
||||
removeDirectory(param.unzipDirectory);
|
||||
param.unzipDirectory.mkdirs();
|
||||
|
||||
HashMap<String, ArrayList<File>> copyList = new HashMap<String, ArrayList<File>>();
|
||||
|
||||
while ((ze = zis.getNextEntry()) != null)
|
||||
{
|
||||
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry ze = entries.nextElement();
|
||||
String fn = ze.getName();
|
||||
|
||||
if (fn.equals("__diff.json")) {
|
||||
foundDiff = true;
|
||||
// copy files from assets
|
||||
byte[] bytes = readBytes(zis);
|
||||
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
||||
String json = new String(bytes, "UTF-8");
|
||||
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
||||
|
||||
@@ -348,8 +333,8 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
}
|
||||
if (fn.equals("index.bundlejs.patch")) {
|
||||
foundBundlePatch = true;
|
||||
|
||||
byte[] patched = hdiffPatch(readOriginBundle(), readBytes(zis));
|
||||
|
||||
byte[] patched = hdiffPatch(readOriginBundle(), readBytes(zipFile.getInputStream(ze)));
|
||||
|
||||
FileOutputStream fout = new FileOutputStream(new File(param.unzipDirectory, "index.bundlejs"));
|
||||
fout.write(patched);
|
||||
@@ -367,10 +352,12 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
unzipToFile(zis, fmd);
|
||||
zipFile.unzipToFile(ze, fmd);
|
||||
}
|
||||
|
||||
zis.close();
|
||||
zipFile.close();
|
||||
|
||||
|
||||
if (!foundDiff) {
|
||||
throw new Error("diff.json not found");
|
||||
}
|
||||
@@ -389,24 +376,25 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
private void doPatchFromPpk(DownloadTaskParams param) throws IOException, JSONException {
|
||||
downloadFile(param);
|
||||
|
||||
ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new FileInputStream(param.targetFile)));
|
||||
ZipEntry ze;
|
||||
removeDirectory(param.unzipDirectory);
|
||||
param.unzipDirectory.mkdirs();
|
||||
|
||||
int count;
|
||||
String filename;
|
||||
boolean foundDiff = false;
|
||||
boolean foundBundlePatch = false;
|
||||
|
||||
removeDirectory(param.unzipDirectory);
|
||||
param.unzipDirectory.mkdirs();
|
||||
|
||||
while ((ze = zis.getNextEntry()) != null)
|
||||
{
|
||||
SafeZipFile zipFile = new SafeZipFile(param.targetFile);
|
||||
Enumeration<? extends ZipEntry> entries = zipFile.entries();
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry ze = entries.nextElement();
|
||||
String fn = ze.getName();
|
||||
|
||||
if (fn.equals("__diff.json")) {
|
||||
foundDiff = true;
|
||||
// copy files from assets
|
||||
byte[] bytes = readBytes(zis);
|
||||
byte[] bytes = readBytes(zipFile.getInputStream(ze));
|
||||
String json = new String(bytes, "UTF-8");
|
||||
JSONObject obj = (JSONObject)new JSONTokener(json).nextValue();
|
||||
|
||||
@@ -426,8 +414,8 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
}
|
||||
if (fn.equals("index.bundlejs.patch")) {
|
||||
foundBundlePatch = true;
|
||||
byte[] patched = hdiffPatch(readFile(new File(param.originDirectory, "index.bundlejs")), readBytes(zis));
|
||||
|
||||
byte[] patched = hdiffPatch(readFile(new File(param.originDirectory, "index.bundlejs")), readBytes(zipFile.getInputStream(ze)));
|
||||
|
||||
FileOutputStream fout = new FileOutputStream(new File(param.unzipDirectory, "index.bundlejs"));
|
||||
fout.write(patched);
|
||||
fout.close();
|
||||
@@ -444,10 +432,10 @@ class DownloadTask extends AsyncTask<DownloadTaskParams, long[], Void> {
|
||||
continue;
|
||||
}
|
||||
|
||||
unzipToFile(zis, fmd);
|
||||
zipFile.unzipToFile(ze, fmd);
|
||||
}
|
||||
|
||||
zis.close();
|
||||
zipFile.close();
|
||||
|
||||
if (!foundDiff) {
|
||||
throw new Error("diff.json not found");
|
||||
|
@@ -0,0 +1,82 @@
|
||||
package cn.reactnative.modules.update;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class SafeZipFile extends ZipFile {
|
||||
|
||||
public SafeZipFile(File file) throws IOException {
|
||||
super(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Enumeration<? extends ZipEntry> entries() {
|
||||
return new SafeZipEntryIterator(super.entries());
|
||||
}
|
||||
|
||||
private static class SafeZipEntryIterator implements Enumeration<ZipEntry> {
|
||||
|
||||
final private Enumeration<? extends ZipEntry> delegate;
|
||||
|
||||
private SafeZipEntryIterator(Enumeration<? extends ZipEntry> delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements() {
|
||||
return delegate.hasMoreElements();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipEntry nextElement() {
|
||||
ZipEntry entry = delegate.nextElement();
|
||||
if (null != entry) {
|
||||
String name = entry.getName();
|
||||
/**
|
||||
* avoid ZipperDown
|
||||
*/
|
||||
if (null != name && (name.contains("../") || name.contains("..\\"))) {
|
||||
throw new SecurityException("illegal entry: " + entry.getName());
|
||||
}
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
|
||||
public void unzipToFile(ZipEntry entry, File output) throws IOException {
|
||||
InputStream inputStream = null;
|
||||
try {
|
||||
inputStream = getInputStream(entry);
|
||||
writeOutInputStream(output, inputStream);
|
||||
} finally {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeOutInputStream(File file, InputStream inputStream) throws IOException {
|
||||
BufferedOutputStream output = null;
|
||||
try {
|
||||
output = new BufferedOutputStream(
|
||||
new FileOutputStream(file));
|
||||
BufferedInputStream input = new BufferedInputStream(inputStream);
|
||||
byte b[] = new byte[8192];
|
||||
int n;
|
||||
while ((n = input.read(b, 0, 8192)) >= 0) {
|
||||
output.write(b, 0, n);
|
||||
}
|
||||
} finally {
|
||||
if (output != null) {
|
||||
output.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "react-native-update",
|
||||
"version": "6.1.0",
|
||||
"version": "6.2.0",
|
||||
"description": "react-native hot update",
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
Reference in New Issue
Block a user