react-native android 更新提示,獲取權(quán)限,自動下載apk

import {
    AsyncStorage, FlatList, Image, StatusBar, TouchableOpacity, View, Dimensions,ToastAndroid,
    ActivityIndicator, Platform, ProgressBarAndroid, Text, PixelRatio,ImageBackground,BackHandler,
    NativeModules,Modal,PermissionsAndroid,
} from "react-native";
import React from "react";

class HomeScreen extends React.PureComponent {
   


  

    componentDidMount() {
      if (Platform.OS === 'android') {
        this._version();
      }
   }


constructor(props) {
        super(props);
        this.state = {
            sourceData : []
            isLoading: false,
            animating: false,
            //網(wǎng)絡(luò)請求狀態(tài)
            error: false,
            errorInfo: "",
            isUpdateModalVisable:false,
        }
    }

render() {
        return (
            <View style={{flex:1,backgroundColor:'#FFFFFF'}}>
                <View style={{flex:1, backgroundColor:'#c4c4c4'}}>

<FlatList
                        ref={(flatList)=>this._flatList = flatList}
                        style={{backgroundColor:'#fff'}}
                        renderItem={this._renderItem}
                        keyExtractor={ this._keyExtractor }
                        refreshing={false}
                        numColumns ={3}
                        data={this.state.sourceData}>
                    </FlatList>
                    <Modal
                        animationType="none"
                        visible={this.state.isUpdateModalVisable}
                        transparent={true}
                        onRequestClose={() => {
                            this.setState({
                                isUpdateModalVisable: false
                            });
                        }}
                    >
                        {this._renderUpdateModal()}
                    </Modal>
                </View>


               
            </View>
        );
    }



_version(){
      
      // let version = 2;
      // if(version){
      //   NativeModules.VersionModule.getVersionInfo((result) => {
      //     if(result){
      //       let o = JSON.parse(result);
      //       if(o){
      //         let versionCode = o.versionCode;
      //         if(versionCode){
      //           if(version>versionCode){
                  
      //             this.setState({
      //               isNeedUpdate:true,
      //             })
      //           }
      //         }
      //       }
            
      //     }
      //   })
      // }

 
      let url = 'http';
      fetch(url)
      .then((response) => response.json())
      .then((responseData) => {
        let resultMsg = responseData.resultMsg;
        let resultCode = responseData.resultCode;


        
        if(resultCode===200){
          let object = responseData.object;
          if(object){
            let version = object.version;
            if(version){
              NativeModules.VersionModule.getVersionInfo((result) => {
                if(result){
                  let o = JSON.parse(result);
                  if(o){
                    let versionCode = o.versionCode;
                    if(versionCode){
                      if(version>versionCode){
                        this.setState({
                          isUpdateModalVisable:true,
                        })
                        
                      }
                    }
                  }
                  
                }
              })
            }
           
          }
           

        }else{
          // this.setState({
          //     error: true,
          // });
        }
      }).catch((error) => {

      });
    }

    _renderUpdateModal(){

      return(


        <View style={{ flex:1, justifyContent: 'center',backgroundColor:'rgba(0, 0, 0, 0.5)', }}>

        <View style={{
          height: 230,
            backgroundColor: '#fff',
            marginLeft:10,
            marginRight:10,
            borderRadius: 5, }}>
            <View style={{
                flex:1, height: 40,
                flexDirection: 'row', paddingLeft: 10,
                justifyContent: 'center', alignItems: 'center'
            }}>
                <TouchableOpacity
                    onPress={() => {this.setState({isUpdateModalVisable:false})}}
                    style={{
                        position: 'absolute', left: 10,
                        height: 40, flexDirection: 'row',
                        justifyContent: 'center', alignItems: 'center', marginLeft: 5
                    }}>
                    <Text style={{ fontSize: 14, color: '#333333', marginLeft: 5 }}>close</Text>
                </TouchableOpacity>
                <Text style={{ position: 'absolute', fontSize: 16, color: '#333333', fontWeight: '600' }}>Tip</Text>
            </View>

            <Text ref={ref => this.textInput = ref}
                style={{
                     marginLeft: 15,marginRight:15,
                    height: 120, color: '#333333', fontSize: 15,
                    borderWidth: 1, borderColor: '#E8EEF0', backgroundColor: '#ffffff', borderRadius: 4,
                    paddingLeft: 15, paddingRight: 15, paddingTop: 10
                }}
                >New version detected, update now?</Text>

                



            <View style={{
                flex:1, height: 40, paddingRight: 15,
                justifyContent: 'center', alignItems: 'flex-end'
            }}>
                <TouchableOpacity
                    onPress={() => {
                      
                      this.checkPermission();


                    }}
                    style={{
                        paddingTop:8,paddingBottom:8,paddingLeft:12,paddingRight:12,
                        justifyContent: 'center', alignItems: 'center',
                        backgroundColor: "#1097D5", borderRadius: 4
                    }}>
                    <Text style={{ fontSize: 15, color: "#FFFFFF" }}>update</Text>
                </TouchableOpacity>
            </View>
            </View>
        </View> );
    }


    checkPermission() {
      this.setState({isUpdateModalVisable:false});
      try {
          //返回Promise類型
          const granted = PermissionsAndroid.check(
              PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
          )
          granted.then((data)=>{
              //alert(data)
              if(data){
                NativeModules.VersionModule.update();
              }else{
                this.requestReadPermission();
              }
          }).catch((err)=>{
              //this.show(err.toString())
          })
      } catch (err) {
          //this.show(err.toString())
      }
  }

  async requestReadPermission() {
    try {
        //返回string類型
        const granted = await PermissionsAndroid.request(
            PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE
            // {
            //     //第一次請求拒絕后提示用戶你為什么要這個權(quán)限
            //     'title': 'Need to storage permissions ',
            //     'message': 'Please agree with storage permissions '
            // }
        )
        if (granted === PermissionsAndroid.RESULTS.GRANTED) {
            //this.show("你已獲取了讀寫權(quán)限")
            NativeModules.VersionModule.update();
        } else {
            //this.show("獲取讀寫權(quán)限失敗")
            alert('Failed to get storage permission')
        }
    } catch (err) {
        //this.show(err.toString())
        alert(err.toString())
    }
}

}



VersionModule.java


import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;

import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

import org.json.JSONException;
import org.json.JSONObject;

public class VersionModule extends ReactContextBaseJavaModule {

    private Context context;

    public VersionModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.context = reactContext;
    }

    @Override
    public String getName() {
        return "VersionModule";
    }

    @ReactMethod
    public void update() {
        if (context != null) {
            Intent intent = new Intent(context, UpdateService.class);
            context.startService(intent);
        }
    }


    public static int getVersionCode(Context mContext) {
        if (mContext != null) {
            try {
                return mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionCode;
            } catch (PackageManager.NameNotFoundException ignored) {
            }
        }
        return 0;
    }

    public static String getVersionName(Context mContext) {
        if (mContext != null) {
            try {
                return mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;
            } catch (PackageManager.NameNotFoundException ignored) {
            }
        }

        return "";
    }

    @ReactMethod
    public void getVersionInfo(final Callback callback) {
        JSONObject versionInfo = new JSONObject();
        try {
            versionInfo.put("versionCode", getVersionCode(context));
            versionInfo.put("versionName", getVersionName(context));
        } catch (JSONException e) {
            e.printStackTrace();
        }
        callback.invoke(versionInfo.toString());
    }
}

VersionPackage.java

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
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 VersionPackage implements ReactPackage {

    public VersionPackage() {}

    @Override
    public List<NativeModule> createNativeModules(
            ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new VersionModule(reactContext));
        return modules;
    }

    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

在MainApplication.java中注冊


@Override
    protected List<ReactPackage> getPackages() {
      return Arrays.<ReactPackage>asList(
          new MainReactPackage(),
          new VersionPackage()
      );
    }

UpdateService.java


import android.Manifest;
import android.app.DownloadManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.IBinder;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.ServiceCompat;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AlertDialog;
import android.webkit.MimeTypeMap;
import android.widget.Toast;


import java.io.File;


public class UpdateService extends Service {


    /**
     * 安卓系統(tǒng)下載類
     **/
    private DownloadManager manager;
    /**
     * 接收下載完的廣播
     **/
    private DownloadCompleteReceiver receiver;
    private String downloadurl;
    private String DOWNLOADPATH = Environment.DIRECTORY_DOWNLOADS;
    private String apkName = "download.apk";

    /**
     * 初始化下載器
     **/
    private void initDownManager() {
        manager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        receiver = new DownloadCompleteReceiver();
        //設(shè)置下載地址
        DownloadManager.Request down = new DownloadManager.Request(Uri.parse(downloadurl));
        // 設(shè)置允許使用的網(wǎng)絡(luò)類型,這里是移動網(wǎng)絡(luò)和wifi都可以
        down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE
                | DownloadManager.Request.NETWORK_WIFI);
        down.setAllowedOverRoaming(false);
        MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
        String mimeString = mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(downloadurl));
        down.setMimeType(mimeString);
        // 下載時,通知欄顯示途中
        down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        // 顯示下載界面
        down.setVisibleInDownloadsUi(true);
        // 設(shè)置下載后文件存放的位置
        down.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, apkName);
        down.setTitle(this.getResources().getString(R.string.app_name));
        // 將下載請求放入隊列
        manager.enqueue(down);
        //注冊下載廣播
        registerReceiver(receiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        //downloadurl = intent.getStringExtra("url");
        downloadurl = "http://127.0.0.1/download.apk";
        File file = new File(
                Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                , apkName);
        if (file.exists()) {
            file.delete();
        }
        try {
            // 調(diào)用下載
            initDownManager();
        } catch (Exception e) {
            e.printStackTrace();
            Toast.makeText(getApplicationContext(), "download fail initDownManager", Toast.LENGTH_SHORT).show();
        }
        return Service.START_NOT_STICKY;
    }

    @Override
    public IBinder onBind(Intent intent) {

        return null;
    }

    @Override
    public void onDestroy() {
        if (receiver != null)
            // 注銷下載廣播
            unregisterReceiver(receiver);
        super.onDestroy();
    }

    // 接受下載完成后的intent
    class DownloadCompleteReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {

            //判斷是否下載完成的廣播
            if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                //獲取下載的文件id
                long downId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                if ( manager.getUriForDownloadedFile(downId) != null ) {
                    //自動安裝apk
                    //installAPK(manager.getUriForDownloadedFile(downId), context);
                    //File file = new File(DOWNLOADPATH+ apkName);
                    install(context);
                    //installAPK(context);
                } else {
                    Toast.makeText(context, "download fail", Toast.LENGTH_SHORT).show();
                }
                //停止服務(wù)并關(guān)閉廣播
                UpdateService.this.stopSelf();
            }
        }



        /**
         * 通過隱式意圖調(diào)用系統(tǒng)安裝程序安裝APK
         */
        public  void install(Context context) {
            File file = new File(
                    Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
                    , apkName);

            if(file.exists()){
                Intent intent = new Intent(Intent.ACTION_VIEW);
                // 由于沒有在Activity環(huán)境下啟動Activity,設(shè)置下面的標(biāo)簽
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.N) { //判讀版本是否在7.0以上
                    //參數(shù)1 上下文, 參數(shù)2 Provider主機地址 和配置文件中保持一致   參數(shù)3  共享的文件
                    Uri apkUri =
                            MyFileProvider.getUriForFile(context, context.getPackageName()+".fileprovider", file);
                    //添加這一句表示對目標(biāo)應(yīng)用臨時授權(quán)該Uri所代表的文件
                    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
                }else{
                    intent.setDataAndType(Uri.fromFile(file),
                            "application/vnd.android.package-archive");
                }
                context.startActivity(intent);
            }else {
                Toast.makeText(context, "update error", Toast.LENGTH_SHORT).show();
            }

        }
    }
}

MyFileProvider.java


import android.support.v4.content.FileProvider;

public class MyFileProvider extends FileProvider {
}

file_provider_paths.xml


<?xml version="1.0" encoding="utf-8"?>
<paths>

    <files-path name="apkdownload" path="apk" />
    <external-path name="Pictures" path="."/>
    <external-path name="image" path="DCIM/Camera/" />
    <root-path path="" name="camera_photos" />
    <external-path  path="." name="Download"/>
</paths>

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

    <application
      android:name=".MainApplication"
      android:label="@string/app_name"
      android:icon="@mipmap/ic_launcher"
      android:allowBackup="true"
      android:theme="@style/AppTheme">
<service
            android:name=".update.UpdateService"
            android:enabled="true" />
        <provider
            android:name=".update.MyFileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_provider_paths" />
        </provider>
</application>

</manifest>
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • mean to add the formatted="false" attribute?.[ 46% 47325/...
    ProZoom閱讀 3,204評論 0 3
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,568評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,052評論 25 709
  • 8天的假期忽悠過去了,明天開始又是嚴(yán)陣以待的上班上學(xué),做好食品供應(yīng)的準(zhǔn)備工作是食堂大媽的必修功課,開始面食制作。 ...
    超級瑪麗_e34c閱讀 303評論 0 0
  • 背上行囊,孤單旅行,享受一場華麗的寂寞。行走在未知的路上,心兒便像風(fēng)兒一樣自由。山巒,河流,峽谷,森林,走...
    冰夫閱讀 197評論 0 0

友情鏈接更多精彩內(nèi)容