歡迎來到安信科技官方網站!【www.boomerlogic.com】
      18112005550
      工作時間: 8:30-21:30
      新聞中心
      News Center

      Android開發中使用FileProvider解決apk升級包無法安裝的問題

      資訊分類: 移動微信  瀏覽: 2023年11月29日

      Android使用FileProvider解決apk無法安裝的問題

      安卓開發APP,需要提供APP升級包安裝時,提示出現下面的問題:

      W/System.err: android.os.FileUriExposedException: file:///xxxx/xxxx/xxxx/updata.apk exposed beyond app through Intent.getData()

      上面的錯誤代碼中:updata.apk為升級包。
      通用使用下面的方法解決處理:

      1.配置mainfest信息,在mainfest的application結點內添加如下代碼:
      android:name="androidx.core.content.FileProvider"
      android:authorities="com.anxin.myapp.fileprovider"
      android:exported="false"
      android:grantUriPermissions="true"
      tools:ignore="WrongManifestParent">
      android:name="android.support.FILE_PROVIDER_PATHS"
      android:resource="@xml/filepaths" />


      上面的代碼中:
      android:authorities 這里使用的是包名。這個其實可以隨便寫,換成自己的包名就都可以。
      android:resource 這里配置一個 xml文件。命名為:filepaths.

      2.在xml下創建filepaths.xml文件如下:
      <paths>
          <external-path name="." path="."/>
      </paths>


      以下代碼說明:
      external-path 是放到sd卡的目錄下 Environment.getExternalStorageDirectory()
      path="." 代表共享 sd卡下的所有目錄。會遍歷sd卡下的所有目錄,來匹配你要安裝 的apk 的目錄。。
      name="." 代表apk存放目錄下所有apk的名字都會遍歷一遍,然后跟你要安裝的apk進行匹配

      3.以下是判斷遠程升級包版本號,并下載、安裝升級包APP的代碼:

      public class Updateapk extends BaseData {
      Context context;
      private RadioGroup mRg;
      ImageView iv_back;
      String url="http://遠程服務器/getjson/getnewversion";
      TextView tv_versionName,tv_versioninfo;
      Button btn_backusercenter;
      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.updateapk);
      initRadioGroup();
      findViewById();
      loadData(url);
      }
      private void findViewById() {
      iv_back=findViewById(R.id.iv_back);
      iv_back.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
      finish();
      }
      });
      btn_backusercenter=findViewById(R.id.btn_backusercenter);
      btn_backusercenter.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
      finish();
      }
      });
      }
      @Override
      public void onSuccess(String result) {
      try {
      parseShowData(result);
      } catch (PackageManager.NameNotFoundException e) {
      e.printStackTrace();
      }
      }

      private void parseShowData(String result) throws PackageManager.NameNotFoundException {
      BeanUpdate bean=new Gson().fromJson(result,BeanUpdate.class);
      Integer serviceVersionCode= bean.getServiceversionCode();
      String serviceversionName=bean.getServiceversionName();
      String serviceversionInfo=bean.getServiceversionInfo();
      tv_versionName=findViewById(R.id.tv_versionName);
      tv_versionName.setText("新版本待升級,新版本號:"+serviceversionName);
      tv_versioninfo=findViewById(R.id.tv_versioninfo);
      tv_versioninfo.setText(serviceversionInfo);
      if (getVersionCode() < serviceVersionCode) {
      showDialogUpdate();

      }else{
      Toast.makeText(this,"當前已經是最新的版本", Toast.LENGTH_SHORT).show();
      }
      }
      private void showDialogUpdate() {
      AlertDialog.Builder builder = new AlertDialog.Builder(this);
      builder.setTitle("版本升級").
      setIcon(R.mipmap.ic_launcher).
      setMessage("發現新版本!請及時更新").
      setPositiveButton("確定", new DialogInterface.OnClickListener() {

      @Override
      public void onClick(DialogInterface dialog, int which) {
      loadNewVersionProgress();//下載最新的版本程序
      }
      }).
      setNegativeButton("取消", new DialogInterface.OnClickListener() {
      @Override
      public void onClick(DialogInterface dialog, int which) {
      Intent intent=new Intent();
      intent.setClass(Updateapk.this, UserCenter.class);
      startActivity(intent);
      }
      });
      AlertDialog alertDialog = builder.create();
      alertDialog.show();
      }
      /**
      * 下載新版本程序,需要子線程
      */
      private void loadNewVersionProgress() {
      final String uri="http://xxxx.xxxx.com/updata.apk";
      final ProgressDialog pd;//進度條對話框
      pd = new  ProgressDialog(this);
      pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
      pd.setMessage("正在下載更新");
      pd.show();
      //啟動子線程下載任務
      new Thread(){
      @Override
      public void run() {
      try {
      File file = getFileFromServer(uri, pd);
      sleep(3000);
      installApk(file);
      pd.dismiss();
      } catch (Exception e) {
      Toast.makeText(getApplicationContext(), "下載新版本失敗", Toast.LENGTH_LONG).show();
      e.printStackTrace();
      }
      }}.start();
      }
      /**
      * 從服務器獲取apk文件的代碼
      * 傳入網址uri,進度條對象即可獲得一個File文件(要在子線程中執行哦)
      */
      public static File getFileFromServer(String uri, ProgressDialog pd) throws Exception{
      if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
      URL url = new URL(uri);
      HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
      conn.setConnectTimeout(5000);
      pd.setMax(conn.getContentLength());
      InputStream is = conn.getInputStream();
      long time= System.currentTimeMillis();
      File file = new File(Environment.getExternalStorageDirectory()+"/Download/", time+"updata.apk");
      FileOutputStream fos = new FileOutputStream(file);
      BufferedInputStream bis = new BufferedInputStream(is);
      byte[] buffer = new byte[1024];
      int len ;
      int total=0;
      while((len =bis.read(buffer))!=-1){
      fos.write(buffer, 0, len);
      total+= len;
      pd.setProgress(total);
      }
      fos.close();
      bis.close();
      is.close();
      return file;
      }
      else{
      return null;
      }
      }

      /**
      * 安裝apk
      *
      * @param file
      */
      private void installApk(File file) {
      //File file = new File(fileSavePath);
      Intent intent = new Intent(Intent.ACTION_VIEW);
      intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      Uri data;
      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//判斷版本大于等于7.0
      // "com.anxin.loveenglish.fileprovider"即是在清單文件中配置的authorities
      // 通過FileProvider創建一個content類型的Uri
      data = FileProvider.getUriForFile(this, "com.anxin.loveenglish.fileprovider", file);
      intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);// 給目標應用一個臨時授權
      } else {
      data = Uri.fromFile(file);
      }
      intent.setDataAndType(data, "application/vnd.android.package-archive");
      startActivity(intent);
      }

      @Override
      public void onError(Throwable ex, boolean isOnCallback) {
      Toast toast =Toast.makeText(this, "當前為最新版本,不需要升級!", Toast.LENGTH_SHORT);
      toast.setGravity(Gravity.CENTER, 0, 0);
      toast.show();
      Intent intent=new Intent();
      intent.setClass(Updateapk.this, UserCenter.class);
      startActivity(intent);
      }

      /*獲取當前程序的版本號*/

      private int getVersionCode() throws PackageManager.NameNotFoundException {
      //獲取packagemanager的實例
      PackageManager packageManager = getPackageManager();
      //getPackageName()是你當前類的包名,0代表是獲取版本信息
      PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0);
      return packInfo.versionCode;
      }
      }


      最后說明下,http://遠程服務器/getjson/getnewversion

      這里獲取的是遠程服務器中設置的APP新版本信息,以tp6.0為例:

      class Getjson extends Base{
      public function getnewversion(){
      $data['serviceversionName']='1.2.0';
      $data['serviceversionCode']=2;
      $data['serviceversionInfo']='最新版本說明文字';
      return json($data);
      }

      上面的代碼:serviceversionCode使用自然數,不要使用帶小數點。

      Copyright © 2007-2022 安信科技(十五周年紀念版) All Rights Reserved  備案號:蘇ICP備15047094號-3 
      網站首頁 |  新聞資訊 |  服務項目 |  軟件產品 |  試用下載 |  需求提交 |  模版建站 |  關于安信 |  產品授權 |  聯系我們 |  定制開發 | 
      服務熱線:181-1200-5550  客服QQ: 120094883  | 郵箱:120094883#qq.com(#改@)