react-native android实现内更新

主要是原生实现的,然后和js进行一个通信。

1,首先在android/app/src/main/AndroidManifest.xml,appapplication标签里添加

//权限需要这几个
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
	.........
	//添加一下代码
      <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="com.project.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths_public" />
        </provider>

2,创建rn类文件

// CustomPackage.java
package com.project; // 包名
import androidx.annotation.NonNull;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CustomPackage implements ReactPackage {
  private List<NativeModule> nativeModuleList;
  @NonNull
    @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Collections.emptyList();
  }
  @NonNull
    @Override
  public List<NativeModule> createNativeModules(
                              ReactApplicationContext reactContext) {
    List<NativeModule> nativeModuleList = new ArrayList<>();
    nativeModuleList.add(new MyNativeModule(reactContext));
    return nativeModuleList;
  }
}

3,创建桥文件,并声明原生下载方法download,接收一个下载链接

// MyNativeModule.java
package com.project; // 包名
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;
import androidx.annotation.NonNull;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.internal.connection.RealCall;
public class MyNativeModule extends ReactContextBaseJavaModule {
    private static ReactApplicationContext reactContext;
    public MyNativeModule(ReactApplicationContext context) {
        super(context);
        reactContext = context;
    }
     @Override
    public String getName() {
        return "MyNativeModule";  // 此处为rn里调用原生模块时的名字
    }
     @ReactMethod
    public void openNativePage() {
        Log.e("MyNativeModule", "openNativePage: download");
    }
    @ReactMethod
    void download(String url) {
        Log.e("download", url);
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS).build();

        Request request = new Request.Builder().url(url).build();
        Call call = okHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(@NonNull Call call, @NonNull IOException e) {
                Log.e("download", e.toString());
            }

            @Override
            public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
                WriteFileUtils.writeFile(response, new IDownloadListener() {
                    @Override
                    public void start(long max) {
                     getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                                .emit("startDownProgressNum", max + "");
                    }

                    @Override
                    public void loading(long progress) {
                      getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                             .emit("downProgressNum", progress+"");
                    }

                    @Override
                    public void loadFail(String msg) {
                        Log.e("download", msg);
                       getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                              .emit("downProgressNum", "-1");
                    }


                    @Override
                    public void complete(Uri fileUri) {
                       getReactApplicationContext().getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                               .emit("downProgressNum", "100");
                        String path = null;
                        path = Environment.getExternalStoragePublicDirectory(
                                Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                        //  如果是Android 10以上
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                            path =  MainApplication.getInstance().getExternalCacheDir().getPath() + "/temp.apk";
                        } else {
                            path = Environment.getExternalStoragePublicDirectory(
                                    Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + "/temp.apk";
                        }
                        WriteFileUtils.installApk(path,getCurrentActivity());
                    }
                });
            }
        });


    }
}

4,创建下载类IDownloadListener.java和WriteFileUtils.java

package com.project;
import android.net.Uri;
public interface IDownloadListener {
    void start(long max);

    void loading(long progress );

    void loadFail(String msg);

    void complete(Uri fileUri);
}

package com.project;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.util.Log;

import androidx.core.content.FileProvider;



import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import okhttp3.Response;

public class WriteFileUtils {

    /*
    *
    *  val imageCollection = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY)

            val imageDetails = ContentValues().apply {
                put(MediaStore.Images.Media.DISPLAY_NAME, "test")
                put(MediaStore.Images.Media.MIME_TYPE,"image/jpeg")
            }
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI

            val saveUri = resolver.insert(imageCollection, imageDetails)

            val outputStream: OutputStream? = contentResolver.openOutputStream(saveUri!!)
            outputStream?.let {
                it.write(bytes)
                it.close()
            }
    * */
    public static void writeFile(Response response, IDownloadListener downloader) {
        try {
            InputStream is = response.body().byteStream();
            OutputStream fos;
            Uri fileUri = null;
            File file;
            //获取文件总长度
            long totalLength = response.body().contentLength();
            downloader.start(totalLength);

            String downloadUrl = MainApplication.getInstance().getExternalFilesDir(null).getAbsolutePath();
            // 下载文件的路径
            String path = null;
            path = Environment.getExternalStoragePublicDirectory(
                    Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
            //  如果是Android 10以上
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                path =  MainApplication.getInstance().getExternalCacheDir().getPath();
            } else {
                path = Environment.getExternalStoragePublicDirectory(
                        Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
            }


            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                file = new File(path
                        + "/temp.apk");
            } else {

                file = new File(path, "temp.apk");
            }

            fos = new FileOutputStream(file);
            BufferedInputStream bis = new BufferedInputStream(is);
            byte[] buffer = new byte[1024];
            int len;
            int progress = 0;
            while ((len = bis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
                progress += len;
                //此处进行更新操作
                //len即可理解为已下载的字节数
                downloader.loading(progress);
            }
            fos.flush();
            fos.close();
            bis.close();
            is.close();
            downloader.complete(fileUri);
            //此处就代表更新结束
        } catch (Exception e) {
            downloader.loadFail(e.getLocalizedMessage());
        }
    }


    public static void installApk(String path, Activity activity) {
        try {
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            File file = new File(path);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                String authority = activity.getPackageName() + ".fileprovider";
                Uri fileUri = FileProvider.getUriForFile(activity.getApplicationContext(), authority, file);
                intent.setDataAndType(fileUri, "application/vnd.android.package-archive");
            } else {
                intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            }
            activity.startActivityForResult(intent, 0);
        } catch (Exception e) {
            Log.e("errer", e.toString());
        }
    }

}

5,在/android/app/src/main/java/com/project2/MainApplication.java下导入类

//import com.project.CustomPackage;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.internal.http.HttpHeaders;

......
.......
//修改getPackages,和onCreate方法
protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          packages.add(new CustomPackage());
          return packages;
        }
public void onCreate() {
    super.onCreate();
    instance = this;
    // If you opted-in for the New Architecture, we enable the TurboModule system
    ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
     List<ReactPackage> list =getReactNativeHost().getReactInstanceManager().getPackages();
     list.add(new CustomPackage());
  }

.....
//增加以下代码
    private static MainApplication instance;

    public synchronized static MainApplication getInstance(){
        if(null==instance){
            instance = new MainApplication();
        }
        return  instance;
    }

6,增加这个文件android/app/src/main/res/xml/file_paths_public.xml

<?xml version="1.0" encoding="utf-8"?><!--
  Copyright 2017 Zhihu Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
  -->
<paths>
    <root-path
        name="camera_photos"
        path="" />
    <!-- 这个是保存拍照图片的路径,必须配置。 -->
    <external-files-path
        name="images"
        path="Pictures" />
    <external-path
        name="external-path"
        path="." />
    <cache-path
        name="my_cache"
        path="/" />
    <external-cache-path
        name="my_ex_cache"
        path="/" />
    <external-files-path
        name="sdcard"
        path="" />

</paths>

最后在rn里调用就可以了

  useEffect(() => {

    // 注册安卓原生下载通信事件
    DeviceEventEmitter.addListener('startDownProgressNum', (max) => {
      console.log('开始下载');
      setadPackTotalSize(Number(max))
    });
    DeviceEventEmitter.addListener('downProgressNum', (msg) => {
      if (msg == '-1') {
        console.log('下载失败');
      } else if (msg == '100') {
        console.log('下载完成');
        setDownOver(true)
        setAdDownModalShow(false)
      } else if (msg != undefined) {
        if (timerLock.current) return;
        console.log('ddddd', Number(msg));
        setProgressNum(Number(msg))
        timerLock.current = true
        setTimeout(() => {
          // console.log(333);
          timerLock.current = false
        }, 1000)
      }
    });
    return () => {
      DeviceEventEmitter.removeAllListeners('startDownProgressNum');
      DeviceEventEmitter.removeAllListeners('downProgressNum');
    }
  }, [])
	// 调用下载
	NativeModules.MyNativeModule.download(downUrl)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值