1.最新研究react-native android热更新组件react-native-pushy,发现官方例子只有更新成功或失败的回调,没有更新进度回调,所以自己捣鼓一个更新进度获取和显示。
下面是热更新android源码,只有 public void onDownloadCompleted()和public void onDownloadFailed(Throwable error)这两个回调方法。
@ReactMethod
public void downloadUpdate(ReadableMap options, final Promise promise){
String url = options.getString("updateUrl");
String hash = options.getString("hashName");
updateContext.downloadFile(url, hash, new UpdateContext.DownloadFileListener() {
@Override
public void onDownloadCompleted() {
promise.resolve(null);//成功回调
}
@Override
public void onDownloadFailed(Throwable error) {
promise.reject(error);//失败回调
}
});
}
2.因为没有进度回调,怎么办?我想出两个方案:
方案一:回调接口增加一个进度回调方法
public interface DownloadFileListener {
void onDownloadCompleted();
void onDownloadProgress();//进度回调
void onDownloadFailed(Throwable error);
}
方案二:获取下载进度,使用事件方式发送到js这边,通过监听更新进度页面。
3.方案一实现:
downloadFile这个下载方法使用Hander Message 方式发下载进度发送到回调接口 void onDownloadProgress()。onDownloadProgress是一个异步方法,Hander Message也是异步的,感觉不太行。可能有其它方法但是太啰嗦了,所以放弃调。
4.方案二实现:
继续研究官方源码,发现下载类是这个
class DownloadTask extends AsyncTask
关键在付类AsyncTask,AsyncTask是一个抽象类
public abstract class AsyncTask
继续深入研究AsyncTask,AsyncTask有以下重要方法:
protected abstract Result doInBackground(Params... var1);
protected void onPreExecute() {
throw new RuntimeException("Stub!");
}
protected void onPostExecute(Result result) {
throw new RuntimeException("Stub!");
}
protected void onProgressUpdate(Progress... values) {
throw new RuntimeException("Stub!");
}
protected void onCancelled(Result result) {
throw new RuntimeException("Stub!");
}
protected void onCancelled() {
throw new RuntimeException("Stub!");
}
protected final void publishProgress(Progress... values) {
throw new RuntimeException("Stub!");
}
找到了:这两个方法是我们需要的
protected void onProgressUpdate(Progress... values) 下载进度回调
protected final void publishProgress(Progress... values) 发布一个进度信息
5.在DownloadTask.java ,DownloadTask 类代码修改。
5.1覆写protected void onProgressUpdate(Progress... values) 这个方法
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
System.out.println("Progress values" +values[0]);//打印进度
WritableMap params = Arguments.createMap();
params.putString("progress", values[0].toString()); //包装数据
sendEvent("progress", params);//发送一个事件,把数据发出去
}
5.2 private void downloadFile(String url, File writePath) 代码修改
关键代码: 、
int pro=(int)((totalRead*1.0 / (contentLength*1.0))*100);//进度转换成百分比
publishProgress(pro);//发布进度到onProgressUpdate
以下是downloadFile整个方法源码:
private void downloadFile(String url, File writePath) throws IOException {
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url(url).build();
Response response = client.newCall(request).execute();
if (response.code() > 299) {
throw new Error("Server return code " + response.code());
}
ResponseBody body = response.body();
long contentLength = body.contentLength();
BufferedSource source = body.source();
if (writePath.exists()) {
writePath.delete();
}
BufferedSink sink = Okio.buffer(Okio.sink(writePath));
if (UpdateContext.DEBUG) {
Log.d("RNUpdate", "Downloading " + url);
}
long bytesRead = 0;
long totalRead = 0;
while ((bytesRead = source.read(sink.buffer(), DOWNLOAD_CHUNK_SIZE)) != -1) {
totalRead += bytesRead;
if (UpdateContext.DEBUG) {
Log.d("RNUpdate", "Progress " + totalRead + "/" + contentLength);
}
System.out.println("Progress " + totalRead + "/" + contentLength);
int pro=(int)((totalRead*1.0 / (contentLength*1.0))*100);//进度转换成百分比
publishProgress(pro);//发布进度到onProgressUpdate
}
if (totalRead != contentLength) {
throw new Error("Unexpected eof while reading ppk");
}
sink.writeAll(source);
sink.close();
if (UpdateContext.DEBUG) {
Log.d("RNUpdate", "Download finished");
}
}
5.3UpdateModule.java 这个类加个发送事件方法
关键代码:
public static ReactApplicationContext mContext;//定义一个静态 ReactApplicationContext
public UpdateModule(ReactApplicationContext reactContext, UpdateContext updateContext) {
super(reactContext);
this.updateContext = updateContext;
mContext=reactContext;//reactContext赋值mContext
}
//增加静态事件发送
/* 发送事件 */
public static void sendEvent(String eventName, WritableMap params) {
((ReactContext) mContext).getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName,
params);
}
5.4使用事件发送
5.4.1 DownloadTask.java 导包
import static cn.reactnative.modules.update.UpdateModule.sendEvent;
5.4.2发送事件
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
System.out.println("Progress values" +values[0]);//打印进度
WritableMap params = Arguments.createMap();
params.putString("progress", values[0].toString()); //包装数据
sendEvent("progress", params);//发送一个事件,把数据发出去
}
6.js代码接收,android java代码发送的进度数据。
6.1导入DeviceEventEmitter
6.2监听事件
componentDidMount() {
DeviceEventEmitter.addListener('progress', (pro) => {
console.log('Progress' + pro.progress)
this.setState({ progress: pro.progress })
});
}
6.3显示代码
更新进度{this.state.progress}
7.git完整源码 https://github.com/nfq6612/hottest