精华内容
下载资源
问答
  • Android app更新适配安卓10、11版本

    千次阅读 2021-03-25 17:59:15
    并且现在安卓已经更新11版本了,中间有几个版本还需对App内部更新做适配,所以说这里记录一下。本笔记目前适配Android11版本。本文只讲下载和安装的核心,不对更新版本的校验和更新弹框做优化,有需要的可以自行...

    Android app内部更新适配安卓10、11版本

    前言

    ​ App内部更新现在基本每个app中都有,由于安卓各大应用市场不统一,不像Ios那样只有一个应用商城。并且现在安卓已经更新到11版本了,中间有几个版本还需对App内部更新做适配,所以说这里记录一下。本笔记目前适配Android11版本。本文只讲下载和安装的核心,不对更新版本的校验和更新弹出框做优化,有需要的可以自行添加。这里参考了android两位大神的文章https://blog.csdn.net/lmj623565791/article/details/72859156?spm=1001.2014.3001.5502、https://guolin.blog.csdn.net/article/details/105419420。

    在这里插入图片描述

    6.0版本之前

    其实在6.0版本之前是什么都不要做的,直接将apk文件下载到sd卡目录中再调用如下代码就可以了

    File file = new File(Environment.getExternalStorageDirectory(), "testandroid7-debug.apk");
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
    startActivity(intent);
    

    6.0-7.0之间

    到了6.0之后如果将文件存储到sd的目录和读取sd卡下载好的文件中需要申请READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE这两个读写权限。就是Environment.开头调用的这些目录。除了sdcard/Android/data/你的包名下/…这是你app的私有目录无需申请权限。

    7.0之后

    在官方7.0的以上的系统中,尝试传递 file://URI可能会触发FileUriExposedException。而你用之前的sd获得的路径恰好就是这种,接下来说说解决方案:

    1. 在清单文件AndroidManifest.xml配置如下

      <provider
          android:name="androidx.core.content.FileProvider"
          android:authorities="${applicationId}.fileprovider"
          android:exported="false"
          android:grantUriPermissions="true">
          <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/filepaths"/>
      </provider>
      

      name是固定的

      authorities是应用的唯一标识一般用应用的包名再拼上一些随便的字符,

      exported=false固定的,

      grantUriPermissions=true固定的

      meta中的name固定的

      resource这边需要再res下创建一个xml文件夹,在xml文件夹下创建一个文件,文件内容如下

      <?xml version="1.0" encoding="utf-8"?>
      <resources>
         <external-files-path
             name="app"
             path="/updateApp"
             />
      </resources>
      

      可配置标签说明

      <root-path/> 代表设备的根目录new File("/");
      <files-path/> 代表context.getFilesDir()
      <cache-path/> 代表context.getCacheDir()
      <external-path/> 代表Environment.getExternalStorageDirectory()
      <external-files-path>代表context.getExternalFilesDirs()
      <external-cache-path>代表getExternalCacheDirs()
      

      因为我这里用的的sdcard/Android/data/你的包名下/updateApp/updateApp.apk所以无需请求权限,但是这个目录下的文件是会计算到你应用的大小中的并且应用一卸载这里面的内容也会跟着卸载。

      安装apk稍作修改

        private fun getUriForFile(file:File) = if(Build.VERSION.SDK_INT >= 24) getUriForFile24(file) else Uri.fromFile(file)
      
          private fun getUriForFile24(file:File) = FileProvider.getUriForFile(this,"$packageName.fileprovider",file)
      
          private fun setIntentDataAndType(intent: Intent,type:String,file: File,writeAble:Boolean) {
              if(Build.VERSION.SDK_INT >= 24){
                  intent.setDataAndType(getUriForFile(file),type)
                  intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                  if(writeAble) {
                      intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                  }
              }else {
                  intent.setDataAndType(Uri.fromFile(file),type)
              }
          }
      

      调用安装

      File file = new File(Environment.getExternalStorageDirectory(), "testandroid7-debug.apk");
      Intent intent = new Intent(Intent.ACTION_VIEW);
      // 调用上面的方法
      setIntentDataAndType(intent, "application/vnd.android.package-archive",file,true);
      startActivity(intent);
      

      10.0之后

      其实安卓10之后增加了作用域访问权限,已经不能使用之前的那种File(路径)的方式去访问sd卡下的路径了,专门有需要使用contentResolver结合MediaStore去访问,这里不展开讲解。可以去看郭神的文章https://guolin.blog.csdn.net/article/details/105419420而我们为了规避掉这个事情,还是上面的将apk的包下载到自己应用下的目录就可以无需做任何改动。

      我也尝试将apk下载到download下,下载可以,但是我不知道怎么取出来,所以放弃了。有知道的大佬可以告知我一声。

      代码示例

      package com.qmc.update
      
      import android.content.Intent
      import android.net.Uri
      import android.os.Build
      import android.os.Bundle
      import android.util.Log
      import android.widget.Toast
      import androidx.appcompat.app.AppCompatActivity
      import androidx.core.content.FileProvider
      import pub.devrel.easypermissions.EasyPermissions
      import java.io.File
      import java.io.FileOutputStream
      import java.net.HttpURLConnection
      import java.net.URL
      
      
      class MainActivity : AppCompatActivity(),EasyPermissions.PermissionCallbacks {
          val TAG = this.javaClass.simpleName
      
          override fun onCreate(savedInstanceState: Bundle?) {
              super.onCreate(savedInstanceState)
              setContentView(R.layout.activity_main)
              downLoadApp()
          }
      
          private fun downLoadApp() {
              Thread {
                  val url = URL("http://192.168.1.120:3001/yanyue/updateApp.apk")
                  val httpURLConnection = url.openConnection() as HttpURLConnection
                  httpURLConnection.requestMethod = "GET"
                  httpURLConnection.connect()
                  try {
                      val responseCode = httpURLConnection.responseCode
                      if (responseCode == HttpURLConnection.HTTP_OK) {
                          val inputStream = httpURLConnection.inputStream
                          val downLoadPath =
                              getExternalFilesDir(null)?.absolutePath + File.separator + "/updateApp"
                          val file = File(downLoadPath)
                          if(!file.exists()) {
                              file.mkdir()
                          }
                          val outputStream = FileOutputStream("$downLoadPath/update.apk")
                          val byteArray = ByteArray(1024)
                          var count: Int
                          do {
                              count = inputStream.read(byteArray)
                              if (count != -1) {
                                  outputStream.write(byteArray, 0, count)
                              } else {
                                  inputStream.close()
                                  outputStream.close()
                                  break
                              }
                          } while (true)
      					inputStream.close()
                          outputStream.close()
                          val updateFile = File("$downLoadPath/update.apk")
                          if(file.exists()){
                              runOnUiThread {
                                  val installIntent = Intent(Intent.ACTION_VIEW)
                                  setIntentDataAndType(installIntent,"application/vnd.android.package-archive",updateFile,true)
                                  startActivity(installIntent)
                              }
      
                          } else {
                              Log.e(TAG, "downLoadApp: 文件不存在")
                          }
                      }
                  } catch (e: Exception) {
                      Log.e(TAG, "downLoadApp: ${e.message}")
                  }
              }.start()
          }
      
          private fun getUriForFile(file:File) = if(Build.VERSION.SDK_INT >= 24) getUriForFile24(file) else Uri.fromFile(file)
      
          private fun getUriForFile24(file:File) = FileProvider.getUriForFile(this,"$packageName.fileprovider",file)
      
          private fun setIntentDataAndType(intent: Intent,type:String,file: File,writeAble:Boolean) {
              if(Build.VERSION.SDK_INT >= 24){
                  intent.setDataAndType(getUriForFile(file),type)
                  intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                  if(writeAble) {
                      intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                  }
              }else {
                  intent.setDataAndType(Uri.fromFile(file),type)
              }
          }
          override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
             Toast.makeText(this,"权限拒绝",Toast.LENGTH_SHORT).show()
          }
      
          override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
              downLoadApp()
          }
      
          override fun onRequestPermissionsResult(
              requestCode: Int,
              permissions: Array<out String>,
              grantResults: IntArray
          ) {
              super.onRequestPermissionsResult(requestCode, permissions, grantResults)
              EasyPermissions.onRequestPermissionsResult(requestCode,permissions,grantResults,this)
          }
      }
      
      

    在这里插入图片描述

    注意在清单文件中添加网络权限!!!

    展开全文
  • Android安卓应用版本命名规范

    千次阅读 2019-05-07 09:08:58
    Android 设置APP版本号 (1) 在清单文件AndroidManifest.xml中manifest 标签节点中加入android:versionCode和android:versionName的值即可设置应用的版本号。如以下代码: (2) build.gradle(Module:app)配置文件...

    Android 设置APP版本号

    (1) 在清单文件AndroidManifest.xml中manifest 标签节点中加入android:versionCode和android:versionName的值即可设置应用的版本号。如以下代码:
    在这里插入图片描述
    (2) build.gradle(Module:app)配置文件可以同样设置版本号
    (注意:推荐使用build.gradle设置版本号,因为一个方便在build.gradle管理版本号和其他的包名等;另一个是build.gradle和AndroidManifest同时存在时,build.gradle更高,会覆盖掉AndroidManifest里面的版本号配置)
    在这里插入图片描述
    Android应用版本命名规范
    版本控制对于发布新版本和开发中的版本维护有着关键性的作用,版本控制之所以重要的原因如下:
    1.用户在安装APP的时候需要知道详细的版本信息,并且在对已有版本进行升级的时候,能否正确安装新版本都和版本控制有关。
    比如:当手机中安装APP的versionCode=1,升级更新的版本号是2(versionCode=2),此时APP可以正常安装更新。反之,如果手机中当前APP版本号是2,升级的或者从其他渠道获取的同一APP的版本号为1,此时替换安装就会失败。
    这种情况就是说,同一个APP低版本是不能直接覆盖安装手机中已存在的高版本应用(通过版本号(versionCode)来判断)。
    这样就给我们在应用升级维护过程中,提高了软件的可维护性和安全性。
    2.对于其他应用想要搜索或者调用指定版本号和版本名称的应用来说,有了可靠的保证。
    当我们发布在市场上有多个版本的APP的时候,比如不同版本对应不同型号的终端,这时我们可以通过版本控制来找到适合的APP。
    3.对于我们自己的版本更新系统或者第三方的APP市场,也通过版本号和版本名称来找到和用户终端设备或者终端应用相匹配的APP展示给用户。对于第三方APP市场来说,这个 版本更为关键的是,决定对用户下载下来之后的兼容性判断起到一定管控作用。
    所以版本控制不能忽视,我们可以通过有效的版本控制来管控我们发布到市场的应用,以便得到更好的用户体验

    (1) VersionCode
    根据上面的描述,版本号(versioncode)是相对比较重要的一个属性。versionCode是一个Integer类型的值。所以大家在设置的时候,不要将versionCode设置的太大,最好不要超过Integer的取值范围(当然一般也是不会超过的),一般大家在发布自己的第一个应用到市场的时候,版本取值为1(versionCode=1),这也是目前典型和普遍的做法。
    然后,每次发布更新版本时可以递增versionCode的值。上面描述版本控制重要性时也描述过,一个新版本的应用的versionCode不能小于之前旧版本的versionCode值,否则进行替换更新升级时会出错,系统提示无法安装。当然,这也不是强制的,只是正式发布应用时,建议必须考虑的问题。
    此值必须是递增变大的整数,为了比较是否需要更新。常见的有两种命名方式:
    1、数字1,2,3递增法
    2、时间命名法,直接采用发布当前的日期,比如versioncode:20170527
    3、版本控制提交号,此方式便于回滚到对应版本的源代码。

    (2) VersionName
    这是一个值为String类型的属性,一般和VersionCode成对出现。VersionCode是方便程序开发者运行和维护Application而设置的一个有效的值。versionName是一个版本的描述,给用户看的,也是用户放在各个第3方平台上提供给使用者看的一个版本名,可以说是对VersionCode的解释和描述。一般格式可以为:1.1.2(major.minor.point)的形式。

    major是主版本号,一般在软件有重大升级时增长
    minor是次版本号,一般在软件有新功能时增长
    maintenance是维护版本,一般在软件有主要的问题修复后增长
    build构建版本(测试版本一般会用到)

    很多公司对版本命名都有自己的一套规范,例如:
    (SVN是Subversion的简称,是一个开放源代码的版本控制系统)
    • <APP名称><主版本号>.<子版本号><SVN最后提交数> 如:YinLiFang_1.0_10242.apk
    • <APP名称><主版本号>.<子版本号>.<阶段版本号><日期版本号加希腊字母版本号>如: YinLiFang_1.0.0.170517_R.apk
    • <APP名称><主版本号>.<子版本号><日期版本号加希腊字母版本号>如: YinLiFang_1.0.170517_beta.apk
    还有其他一些会在主版本号前加一个 v 等等,大体上想表达的意思都差不多,为了规范命名,为了方便以后管理,为了描述当前的包处于哪个阶段。这里大致介绍下软件版本号的组成部分,上面也给出了一些示例,一般由四部分组成:<主版本号>.<子版本号>.<阶段版本号>.<日期版本号加希腊字母版本号> 。 如:1.1.2.170517_alpha 。
    那么希腊字母版本号是什么意思呢?
    希腊字母版本号共有5种,分别是:base、alpha、beta、rc、release。 完全的版本号定义分三项: <主版本号.><子版本号>.<阶段版本号>(即:1.1.0),下面对版本阶段进行下简单的介绍。


    希腊字母所代表的版本阶段介绍
    Alpha版:也叫α版,此版本主要是以实现软件功能为主,通常只在软件开发者内部交流,一般而言,该版本软件的Bug较多,需要继续修改。
    Beta版:此版本相对于α版已经有了很大的改进,消除了严重的错误,但还是存在着一些缺陷,需要经过多次测试来进一步消除,此版本主要的修改对像是软件的UI。
    RC版(Release Candidate发布候选版本):此版本已经相当成熟了,基本上不存在导致错误的BUG,与即将发行的正式版相差无几,测试人员基本通过的版本。
    Release版:此版本意味着“最终版本”、“上线版本”,在前面版本的一系列测试版之后,终归会有一个正式版本,是最终交付用户使用的一个版本。该版本有时也称为标准版。一般情况下,Release不会以单词形式出现在软件封面上,取而代之的是符号®。


    版本号修改规则
    以 YinLiFang_1.0.0.170517_beta.apk 为例
    Major主版本号(1):当功能模块有较大的变动,比如增加多个模块或者整体架构发生变化。此版本号由项目决定是否修改。
    Minor子版本号(0):当功能有一定的增加或变化,比如增加了对权限控制、增加自定义视图等功能。此版本号由项目决定是否修改。
    Maintenance阶段版本号(0):一般是 Bug 修复或是一些小的变动,要经常发布修订版,时间间隔不限,修复一个严重的bug即可发布一个修订版。此版本号由项目经理决定是否修改。
    日期版本号(170517):用于记录修改项目的当前日期,每天对项目的修改都需要更改日期版本号。此版本号由开发人员决定是否修改。
    希腊字母版本号(beta)::此版本号用于标注当前版本的软件处于哪个开发阶段,当软件进入到另一个阶段时需要修改此版本号。此版本号由项目决定是否修改。

    本文参考来源:
    [1]https://blog.csdn.net/gao_chun/article/details/72417127

    展开全文
  • Android应用中apk下载更新,适用于android 9及以下安卓版本。 直接上代码: 一、在主配置文件中写权限。 <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission ...

    Android应用中apk下载更新,适用于android 9及以下安卓版本。

    直接上代码:

    一、在主配置文件中写权限。

        <uses-permission android:name="android.permission.RECORD_AUDIO" />
        <uses-permission android:name="android.permission.INTERNET" /><!-- 连网必须加的 -->
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <!-- SDCard写权限 -->
        <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <!-- SDCard读权限 -->
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.READ_PHONE_STATE" />
        <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
        <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
        <uses-permission android:name="android.permission.CAMERA" />
        <uses-permission android:name="android.permission.GET_TASKS" />
        <uses-permission android:name="android.permission.MODE_PRIVATE" /> <!-- 创建文件夹 -->
        <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <!-- 安装权限 -->
        <uses-permission android:name="android.permission.READ_CONTACTS" />
        <uses-permission android:name="android.permission.PERMISSION_GRANTED" />
    
      <application> //在此加入
      <provider
                android:name="androidx.core.content.FileProvider"    //也可以引用v4包
                android:authorities="com.example.myapplication1.provider"  //注意.provider前面为你的包名
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/files_paths" />    //在res文件夹下新建package命名为xml,新建xml文件命名为files_paths
            </provider>
    
        </application>
    

    二、创建 files_paths.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <paths>
            <external-path name="renyi" path=""/>
    
        </paths>
    </resources>
    

    三、创建 UpdateVersionController.java

        
        public class UpdateVersionController {
        private Button cancelBtn;
        private Context context;
        private int info;
        private int info3;
        private int versionCode;//当前版本号
        private Dialog dialog; //提示用户更新的dialog
        private ProgressDialog pd;  //下载进度条
    
        public static UpdateVersionController getInstance(Context context) {
            return new UpdateVersionController(context);
        }
    
        public UpdateVersionController(Context context) {
            this.context = context;
        }
     /*
     * 记得运行该方法
     */
        public void forceCheckUpdateInfo(){
            //获取版本号,这个版本号为未更新的版本号
            versionCode = getVerCode(context);
    
             //获取app新版版本信息,添加网络请求
            new Thread(new Runnable() {
                @Override
                public void run() {
                    /*
                     *用的Volley框架,Volley可以自己搜索下载jar包,下面是使用Volley获取GET请求的方法
                     */
                    RequestQueue mQueue= Volley.newRequestQueue(context);
                    JsonObjectRequest mreq=new JsonObjectRequest(Request.Method.GET,“获取版本号的网址”,new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject jsonObject) {
    
                            String  tt=jsonObject.toString();      //把获取的jsonObject转为String类型
    
                            Gson gson=new Gson();                  //这里我用的是Gson解析,可以自己搜索gson的jar包下载使用
                            AppVersion nt=gson.fromJson(tt, AppVersion.class);      //这里的AppVersion是网络获取版本号的网址中json数据的实体类,tt是网络获取的数据,用该方法实现json解析
                            //关于实体类:从服务器网址获取的json数据,通过搜索json自动生成实体类下载复制。并 implement Serializable ,添加构造方法
                            info=nt.getVNumber();                   //通过nt获取实体类里的版本号,为String类型
                            info3=nt.getIsForce();                 //通过nt获取是否强制更新,为String类型
                            Log.e("版本",""+versionCode);//建议输出一下版本号,进行对比
    
    
                            //更新app版本号比对,info新版本号和当前的版本号versionCode做对比,如果新版本号大于本版本就运行更新方法showUpdataDialog()
                            if ( info > versionCode) {
                                showUpdataDialog();
                            } else {
    
                            }
    
    
    
                        }
                    }, new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError volleyError) {
                            Log.e("*****", String.valueOf(volleyError));
                        }
                    });
                    mQueue.add(mreq);
    
    
                }
            }).start();
    
    
        }
    
        /**
         * 弹出对话框提示用户更新
         */
        protected void showUpdataDialog() {
    
            dialog = new Dialog(context, android.R.style.Theme_Dialog);
            dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
            dialog.setContentView(R.layout.activity_updater);
            dialog.setCanceledOnTouchOutside(false);
            dialog.setCancelable(false);
            ((TextView) dialog.findViewById(R.id.content)).setText("是否进行更新?");
            cancelBtn = (Button) dialog.findViewById(R.id.cancel);
            cancelBtn.setVisibility("0".equals(info3) ? View.GONE : View.VISIBLE);
            // 取消更新
            cancelBtn.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.dismiss();
                }
            });
    
            // 确认更新
            dialog.findViewById(R.id.ok).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    dialog.dismiss();
                    downLoadApk();
                }
            });
    
            dialog.show();
        }
    
        /**
         * 步骤三:下载文件
         */
        private void downLoadApk() {
            // 进度条对话框
            pd = new ProgressDialog(context);
            pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            pd.setMessage("下载中...");
            pd.setCanceledOnTouchOutside(false);
            pd.setCancelable(false);
            // 监听返回键--防止下载的时候点击返回
            pd.setOnKeyListener(new OnKeyListener() {
                @Override
                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
                    if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) {
                        Toast.makeText(context, "正在下载请稍后", Toast.LENGTH_SHORT).show();
                        return true;
                    } else {
                        return false;
                    }
                }
            });
            // Sdcard不可用
            if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                Toast.makeText(context, "SD卡不可用", Toast.LENGTH_SHORT).show();
    
            } else {
                pd.show();
                //下载的子线程
                new Thread() {
                    @Override
                    public void run() {
                        try {
                            // 在子线程中下载APK文件
                            File file = getFileFromServer(“下载apk的网址 ”, pd);
                            sleep(1000);
                            // 安装APK文件
                            OpenFileUtil.openFileByPath(context,file.toString());
                            pd.dismiss(); // 结束掉进度条对话框
                        } catch (Exception e) {
                            Toast.makeText(context, "文件下载失败了", Toast.LENGTH_SHORT).show();
                            pd.dismiss();
                            e.printStackTrace();
                        }
                    }
    
                }.start();
            }
        }
    
        /**
         * 从服务器下载apk
         */
        public File getFileFromServer(String path, ProgressDialog pd) throws Exception {
            // 如果相等的话表示当前的sdcard挂载在手机上并且是可用的
            if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                URL url = new URL(path);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setConnectTimeout(5000);
                // 获取到文件的大小
                pd.setMax(conn.getContentLength() / 1024);
                InputStream is = conn.getInputStream();
                String p = PathUtils.path;
                File file = new File(p+ "/update/aaaa.apk");
    
    
              Log.e("File路径",""+file);
    
                //判断文件夹是否被创建
                boolean mkdirs;
                if (!file.getParentFile().exists()) {
                     mkdirs = file.getParentFile().mkdirs();
                }
    
                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 / 1024);
                }
                fos.close();
                bis.close();
                is.close();
                return file;
            } else {
                return null;
            }
        }
    
    
    
    
       /**
       * 获取版本号
        */
        public static int getVerCode(Context context) {
            int verCode = -1;
            try {
                // 获取packagemanager的实例
                PackageManager packageManager = context.getPackageManager();
                // getPackageName()是你当前类的包名,0代表是获取版本信息
                PackageInfo packInfo = packageManager.getPackageInfo(
                        context.getPackageName(), 0);
    
                verCode = packInfo.versionCode;
    
            } catch (Exception e) {
                e.printStackTrace();
            }
            return verCode;
        }
    
    
    }
    
    

    三、创建OpenFileUtil.java 打开任意文件也可以使用该类

    
    public class OpenFileUtil {
        private static final String[][] MATCH_ARRAY={
                //{后缀名,    文件类型}
                {".3gp",    "video/3gpp"},
                {".apk",    "application/vnd.android.package-archive"},
                {".asf",    "video/x-ms-asf"},
                {".avi",    "video/x-msvideo"},
                {".bin",    "application/octet-stream"},
                {".bmp",      "image/bmp"},
                {".c",        "text/plain"},
                {".class",    "application/octet-stream"},
                {".conf",    "text/plain"},
                {".cpp",    "text/plain"},
                {".doc",    "application/msword"},
                {".docx",    "application/msword"},
                {".xls",    "application/msword"},
                {".xlsx",    "application/msword"},
                {".exe",    "application/octet-stream"},
                {".gif",    "image/gif"},
                {".gtar",    "application/x-gtar"},
                {".gz",        "application/x-gzip"},
                {".h",        "text/plain"},
                {".htm",    "text/html"},
                {".html",    "text/html"},
                {".jar",    "application/java-archive"},
                {".java",    "text/plain"},
                {".jpeg",    "image/jpeg"},
                {".jpg",    "image/jpeg"},
                {".js",        "application/x-javascript"},
                {".log",    "text/plain"},
                {".m3u",    "audio/x-mpegurl"},
                {".m4a",    "audio/mp4a-latm"},
                {".m4b",    "audio/mp4a-latm"},
                {".m4p",    "audio/mp4a-latm"},
                {".m4u",    "video/vnd.mpegurl"},
                {".m4v",    "video/x-m4v"},
                {".mov",    "video/quicktime"},
                {".mp2",    "audio/x-mpeg"},
                {".mp3",    "audio/x-mpeg"},
                {".mp4",    "video/mp4"},
                {".mpc",    "application/vnd.mpohun.certificate"},
                {".mpe",    "video/mpeg"},
                {".mpeg",    "video/mpeg"},
                {".mpg",    "video/mpeg"},
                {".mpg4",    "video/mp4"},
                {".mpga",    "audio/mpeg"},
                {".msg",    "application/vnd.ms-outlook"},
                {".ogg",    "audio/ogg"},
                {".pdf",    "application/pdf"},
                {".png",    "image/png"},
                {".pps",    "application/vnd.ms-powerpoint"},
                {".ppt",    "application/vnd.ms-powerpoint"},
                {".prop",    "text/plain"},
                {".rar",    "application/x-rar-compressed"},
                {".rc",        "text/plain"},
                {".rmvb",    "audio/x-pn-realaudio"},
                {".rtf",    "application/rtf"},
                {".sh",        "text/plain"},
                {".tar",    "application/x-tar"},
                {".tgz",    "application/x-compressed"},
                {".txt",    "text/plain"},
                {".wav",    "audio/x-wav"},
                {".wma",    "audio/x-ms-wma"},
                {".wmv",    "audio/x-ms-wmv"},
                {".wps",    "application/vnd.ms-works"},
                {".xml",    "text/plain"},
                {".z",        "application/x-compress"},
                {".zip",    "application/zip"},
                {"",        "*/*"}
        };
    
        /**
         * 根据路径打开文件
         * @param context 上下文
         * @param path 文件路径
         */
        public static void openFileByPath(Context context, String path) {
            if(context==null||path==null)
                return;
            Intent intent = new Intent();
            //设置intent的Action属性
            intent.setAction(Intent.ACTION_VIEW);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            intent.addCategory(Intent.CATEGORY_DEFAULT);
    
            //文件的类型
            String type = "";
            for(int i =0;i < MATCH_ARRAY.length;i++){
                //判断文件的格式
                if(path.contains(MATCH_ARRAY[i][0])){
                    type = MATCH_ARRAY[i][1];
                    break;
                }
            }
            try {
                File out = new File(path);
                Uri fileURI;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    // 由于7.0以后文件访问权限,可以通过定义xml在androidmanifest中申请,也可以直接跳过权限
                    // 通过定义xml在androidmanifest中申请
    //                fileURI = FileProvider.getUriForFile(context,
    //                        "com.lonelypluto.zyw_test.provider",
    //                        out);
                    // 直接跳过权限
                    StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
                    StrictMode.setVmPolicy(builder.build());
                    fileURI = Uri.fromFile(out);
                }else{
                    fileURI = Uri.fromFile(out);
                }
                //设置intent的data和Type属性
                intent.setDataAndType(fileURI, type);
                //跳转
                if (context.getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
                    context.startActivity(intent);
                } else {
                    Toast.makeText(context, "没有找到对应的程序", Toast.LENGTH_SHORT).show();
                }
    
            } catch (Exception e) { //当系统没有携带文件打开软件,提示
                Toast.makeText(context, "无法打开该格式文件", Toast.LENGTH_SHORT).show();
                e.printStackTrace();
            }
        }
    }
    

    三、PathUtils .java

    public class PathUtils {
    
        public static String path = null;
    }
    
    

    四、程序入口MainActivity.java

     private UpdateVersionController controller=new UpdateVersionController(this);
    
    
            @Override
            protected void onCreate(Bundle savedInstanceState) {
                  super.onCreate(savedInstanceState);
                  setContentView(R.layout.activity_main);
                  
                  PathUtils.path = getExternalFilesDir(null).toString();
                  controller.forceCheckUpdateInfo();//运行该方法
            if (Build.VERSION.SDK_INT>=23&&checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
                requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},1);
                requestPermissions(new String[]{Manifest.permission.RECORD_AUDIO},1);
                requestPermissions(new String[]{Manifest.permission.INTERNET},1);
                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},1);
                requestPermissions(new String[]{Manifest.permission.ACCESS_NETWORK_STATE},1);
                requestPermissions(new String[]{Manifest.permission.ACCESS_WIFI_STATE},1);
                requestPermissions(new String[]{Manifest.permission.READ_PHONE_STATE},1);
                requestPermissions(new String[]{Manifest.permission.ACCESS_FINE_LOCATION},1);
                requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
                requestPermissions(new String[]{Manifest.permission.CAMERA},1);
                requestPermissions(new String[]{Manifest.permission.GET_TASKS},1);
                requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES},1);
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},1);
            }
            }
    

    完成了。

    展开全文
  • Android Studio默认编译Release版本apk

    千次阅读 2019-07-13 15:21:48
    在我们打包是进行Make Project,默认编译出来的是Debug包。 在Android Studio的左下角,有一个Build Variants,如图下: 这样Make Project编出来的所有apk都是release版本。 ...

    在我们打包是进行Make Project,默认编译出来的是Debug包。

    在Android Studio的左下角,有一个Build Variants,如图下:
    在这里插入图片描述

    这样Make Project编出来的所有apk都是release版本。

    展开全文
  • 安卓热修复,android打补丁,不用发版本就能实时的解决一些线上版本的bug
  • Over the last few years, Android OS has come to dominate the mobile OS landscape with over 86% market share as of 2019. The system provides high-performing and secure usage and comes with regular vers...
  • 欢迎使用Markdown编辑器写博客我遇到了一些问题,因为我想要集成FB SDK 的登录,分享等功能进入我的项目,facebook-android-sdk在4.0版本后facebook的sdk是给android-studio使用的,但是怎么将facebook-sdk倒入...
  • 本文主要介绍了Android Studio如何查看历史版本号,检版本
  • app现在基本都有版本更新这个功能,实现起来也很简单 截图效果: 1. 获取当前app的版本号 /** * 获取版本号 * * @throws PackageManager.NameNotFoundException */ public static String ...
  • Android版本列表

    万次阅读 2016-08-17 10:48:33
    Android版本列表
  • 今天拿一个用低版本Gradle的编译的Android工程,gradle对版本的向下兼容做的不太好,因此在高版本Gradle的电脑上会很多问题。 1. Error:The project is using an unsupported version of the Android Gradle ...
  • 初学者遇到 Android Studio, 导入工程后, 会出现各种奇葩错误, 如果管理好各个插件, gradle, SDK, SDK Tools, 各种官方依赖库 的版本, 会将错误大大的减少; 这里将常用的 Android Studio 常用的版本管理总结下.
  • 最新的Android版本什么

    千次阅读 2020-09-28 14:02:44
    Android can be confusing. There are a lot of different versions, and many of them are still running on devices today. Keeping up with the latest version can be a challenge, but fret not—we have you ...
  • Android从1.0 6.0各版本的差别

    万次阅读 2016-04-26 17:17:32
    但是还是有些版本的系统还在使用,作为Android程序开发者,必须尽量照顾各种版本的系统,否则你提出的解决方案是不完善的,对于Android开发者来说,很有必要知道android各个版本的特性,这样才能制定更完备的...
  • android更新ADT最新版本出错

    千次阅读 2013-01-18 15:09:26
     昨天新接触了一个技术点:android和i2c通信,由于硬件设备是android4.0.4,而我安装的eclipse android最高版本android4.0.3,查了一下,貌似木有android4.0.4的ADT,所以我觉得更新最新版本(目前android4.2)...
  • Android历史版本

    千次阅读 2016-05-24 20:41:39
    Android历史版本
  • Android 版本大于等于6.0(SDK版本大于等于23),权限需要应用自主申请,动态申请权限。 如果Unity做为Android的子模块,除了应用本身会有申请权限的弹窗之外,Unity也会自动弹权限申请窗口。 关于Android平台...
  • 安卓4以前的版本不作为讨论对象,在安卓4之前的版本,谷歌一度想闭源安卓,可惜失败了,而且安卓那时的开放性不高,可设计性也不高。而且手机普及性不高,流量少,市场趋势还没有趋向移动端发展。 一、安卓4.X 1...
  • com.android.support版本冲突的解决办法

    万次阅读 多人点赞 2017-10-12 14:49:59
    All com.android.support libraries must use the exact same version specification (mixing versions can lead to runtime crashes 当我们使用android studio添加一些第三方的依赖库时,很可能会提示...的包版本号要
  • Android OS历史版本

    千次阅读 2018-02-19 00:14:01
    文章共约2000字,阅读需要约5分钟说起Android OS,大家都知道是Google的Android,但是Google却不是Android的“亲生父亲”。最初的Android OS,由酷爱机器人的Andy Rubin(安迪鲁宾)所研发。因为酷爱机器人,所以...
  • android版本列表

    千次阅读 2017-08-14 09:37:40
    代号、标记和细分版本 (Build) 号简要来说,Android 的开发是围绕着版本系列进行的,这些版本使用美味的点心名字(按字母顺序)作为代号。平台代号、版本、API 级别和 NDK 版本为方便起见,代号与以下版本号、API ...
  • Android版本与Linux内核版本的关系

    万次阅读 2011-08-03 16:14:30
    Android版本与Linux内核版本的关系   一.Android版本与Linux内核的关系 英文名 中文名 Android版本 Linux内核版本 No 无 1.1 C
  • 迁移 Gradle 项目1.0.0 版本 Android 的 Gradle 插件有了迅猛的发展,作为进化的特征,API 和构建文件的描述语言也经过了一些不兼容的更改。如果你正在试图加载用旧版本的 Gradle 插件构建的项目,它可能无法通过 ...
  • 修改android 系统设置 android 版本

    千次阅读 2017-04-05 10:17:11
    修改android 系统设置 android 版本 http://blog.csdn.net/haplwd/article/details/10226039 Android 中的设置关于手机中的型号的更改 1.APPS-->Settings-->About phone-->Model number 通过Model ...
  • 自从cocos2dx 的cocos studio 在3.10版本停止更新后,cocos2dx的很多东西都要自己弄了。 前段时间需要接入一个第三方的sdk lib,这个玩意...抱着试试看的态度~~在eclipse里面直接改安卓版本,的确能打包成功,手机也
  • Android 版本大于等于6.0(SDK版本大于等于23),权限需要应用自主申请,动态申请权限。 如果Unity做为Android的子模块,除了应用本身会有申请权限的弹窗之外,Unity也会自动弹权限申请窗口。 关于Android平台...
  • Android修改APP版本

    万次阅读 2016-09-19 14:28:34
    Android修改APP版本
  • Android版本更替

    万次阅读 2019-07-12 17:48:40
    android 版本迭代发展历程
  • 应用安装包下载完弹安装界面适配Android N及以上版本遇到文件及解决方法   在实现下载和安装APP功能的时候在Android较高版本可能会遇到如下的问题: 安装Apk时报错:android.os.FileUriExposedException: file:...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 282,217
精华内容 112,886
关键字:

安卓出到什么版本了