Anroid App检测版本更新

前言

最近开发有版本更新的需求,然后就研究了下,找到了某位大神的代码 开发中应用版本更新功能 (链接在这里),并在基础上改进了6.0的权限问题,代码仅供参考

简介

大体的思路就是拿到我们本地的版本号去对比后台的版本号,一致不做处理,不一致弹出对话框提示更新

使用

public class AppInnerDownLoder {
    public final static String SD_FOLDER = Environment.getExternalStorageDirectory()+ "/VersionChecker/";
    private static final String TAG = AppInnerDownLoder.class.getSimpleName();

    /**
     * 从服务器中下载APK
     */
    @SuppressWarnings("unused")
    public static void downLoadApk(final Context mContext, final String downURL, final String appName ) {

        final ProgressDialog pd; // 进度条对话框
        pd = new ProgressDialog(mContext);
        pd.setCancelable(false);// 必须一直下载完,不可取消
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.setMessage("正在下载安装包,请稍后");
        pd.setTitle("版本升级");
        pd.show();
        new Thread() {
            @Override
            public void run() {
                try {
                    File file = downloadFile(downURL,appName, pd);
                    sleep(3000);
                    installApk(mContext, file);
                    // 结束掉进度条对话框
                    pd.dismiss();
                } catch (Exception e) {
                    pd.dismiss();

                }
            }
        }.start();
    }

    /**
     * 从服务器下载最新更新文件
     *
     * @param path
     *            下载路径
     * @param pd
     *            进度条
     * @return
     * @throws Exception
     */
    private static File downloadFile(String path,String appName ,ProgressDialog pd) throws Exception {
        // 如果相等的话表示当前的sdcard挂载在手机上并且是可用的
        if (Environment.MEDIA_MOUNTED.equals(Environment
                .getExternalStorageState())) {
            URL url = new URL(path);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            // 获取到文件的大小
            pd.setMax(conn.getContentLength());
            InputStream is = conn.getInputStream();
            String fileName = SD_FOLDER
                    + appName+".apk";
            File file = new File(fileName);
            // 目录不存在创建目录
            if (!file.getParentFile().exists())
                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);
            }
            fos.close();
            bis.close();
            is.close();
            return file;
        } else {
            throw new IOException("未发现有SD卡");
        }
    }

    /**
     * 安装apk
     */
    private static void installApk(Context mContext, File file) {
        Uri fileUri = Uri.fromFile(file);
        Intent it = new Intent();
        it.setAction(Intent.ACTION_VIEW);
        it.setDataAndType(fileUri, "application/vnd.android.package-archive");
        it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);// 防止打不开应用
        mContext.startActivity(it);
    }

    /**
     * 获取应用程序版本(versionName)
     *
     * @return 当前应用的版本号
     */

    private static double getLocalVersion(Context context) {
        PackageManager manager = context.getPackageManager();
        PackageInfo info = null;
        try {
            info = manager.getPackageInfo(context.getPackageName(), 0);
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "获取应用程序版本失败,原因:" + e.getMessage());
            return 0.0;
        }

        return Double.valueOf(info.versionName);
    }
    /**
     * byte(字节)根据长度转成kb(千字节)和mb(兆字节)
     *
     * @param bytes
     * @return
     */
    public static String bytes2kb(long bytes) {
        BigDecimal filesize = new BigDecimal(bytes);
        BigDecimal megabyte = new BigDecimal(1024 * 1024);
        float returnValue = filesize.divide(megabyte, 2, BigDecimal.ROUND_UP)
                .floatValue();
        if (returnValue > 1)
            return (returnValue + "MB");
        BigDecimal kilobyte = new BigDecimal(1024);
        returnValue = filesize.divide(kilobyte, 2, BigDecimal.ROUND_UP)
                .floatValue();
        return (returnValue + "KB");
    }
}

主要的实现功能就在这一个类里面,看懂的朋友恭喜你直接搬走就好了,没看懂的朋友没关系我们一步一步来,详细的在下面:

效果图如下:



我用到的是retrofit+rxjava   MVP+Retrofit+RxJava网络请求框架(这里提供一下我的自学博客)

    配置如下:
     //retrofit2.0
    compile 'com.squareup.retrofit2:retrofit:2.3.0'
    compile 'com.squareup.retrofit2:converter-gson:2.3.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.8.0'
    //rxJava
    compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
    compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
    // RxJava2支持(根据需要选择)
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

Manifest里权限配置

<!--网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 读写权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

请求封装

public class HttpUtil {

    private static Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(Constant.LINK_MAIN)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addCallAdapterFactory(retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory.create())
            .build();


    //get封装
    public static void get(Consumer<String> onNext, Consumer<Throwable> onError, String url) {
        ApiServer api = retrofit.create(ApiServer.class);
        Observable<String> observable = api.getTest(url);
        observable.observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(onNext, onError);

    }
}

请求接口拼接

public interface ApiServer {
    //get请求
    @Headers({"User-Agent:okhttp/3.9.1/Android"})
    @GET()
    Observable<String> getTest(@Url String url);
}

返回数据并进行封装

public class GetPresenter extends BasePresenter<DataView> {

    public <T> void getData(final Class<T> cla, String url) {
        HttpUtil.get(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.e(TAG, "get:"+s);
                T t = Constant.GsonToBean(s, cla);
                getView().callBackData(t);

            }
        }, new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Exception {

            }
        }, url);
    }
}

提供常用接口和方法的类

public class Constant {

    //常用网络访问路径地址
   public static final String LINK_MAIN = "http://127.0.0.1:8081/update";  
 public static final String HEAD_PR = "http://releases.b0.upaiyun.com/hoolay.apk";
 //gson封装 
 public static <T> T GsonToBean(String gsonString, Class<T> cls) 
{ 
    T t = null; 
    if (!TextUtils.isEmpty(gsonString)) 
    { 
        t = gson.fromJson(gsonString, cls); 
    } 
        return t; 
}
}  

封装的BasePresenter

public abstract class BasePresenter <V extends BaseView> {

    protected V mView;

    public V getView() {
        return mView;
    }

    public void attachView(V view){
        this.mView = view;
    }

    public void detachView(){
        this.mView = null;
    }


}

回调父类接口

public interface BaseView {
}

回调的子类接口

public interface DataView <T> extends BaseView {
    void callBackData(T value);
    void callBackDataError(Throwable throwable);
}

网络获取成功封装成bean类(自己根据后台返回的数据封装)

public class VersionUpdateBean {

    /**
     * error_code : 200
     * msg : 成功
     * data : {"version":"1.0.1","content":["更新视频上传功能","更新视频上传功能","更新视频上传功能"]}
     */

    private int error_code;
    private String msg;
    private DataBean data;

    public int getError_code() {
        return error_code;
    }

    public void setError_code(int error_code) {
        this.error_code = error_code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public DataBean getData() {
        return data;
    }

    public void setData(DataBean data) {
        this.data = data;
    }
   ... ...
}

获取当前应用的版本号及版本名称(可直接复制提供使用)

public class APKVersionCodeUtils {
    /**
     * 获取当前本地apk的版本
     *
     * @param mContext
     * @return
     */
    public static int getVersionCode(Context mContext) {
        int versionCode = 0;
        try {
            //获取软件版本号,对应AndroidManifest.xml下android:versionCode
            versionCode = mContext.getPackageManager().
                    getPackageInfo(mContext.getPackageName(), 0).versionCode;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return versionCode;
    }

    /**
     * 获取版本号名称
     *
     * @param context 上下文
     * @return
     */
    public static String getVerName(Context context) {
        String verName = "";
        try {
            verName = context.getPackageManager().
                    getPackageInfo(context.getPackageName(), 0).versionName;
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return verName;
    }
}

6.0动态权限封装(可直接复制提供使用)

public class PermissionUtil {
    /**
     * 是否需要检查权限
     */
    private static boolean needCheckPermission() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
    }

    /**
     * 获取sd存储卡读写权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getExternalStoragePermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }

    /**
     * 获取拍照权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getCameraPermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    /**
     * 获取麦克风权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getAudioPermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.RECORD_AUDIO, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE);
    }
    /**
     * 获取定位权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getLocationPermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.ACCESS_COARSE_LOCATION);
    }
    /**
     * 获取读取联系人权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getContactsPermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.READ_CONTACTS);
    }
    /**
     * 获取发送短信权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getSendSMSPermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.SEND_SMS);
    }
    /**
     * 获取拨打电话权限
     *
     * @return 是否已经获取权限,没有自动申请
     */
    public static boolean getCallPhonePermissions(@NonNull Activity activity, int requestCode) {
        return requestPerssions(activity, requestCode, Manifest.permission.CALL_PHONE);
    }







    public static List<String> getDeniedPermissions(@NonNull Activity activity, @NonNull String... permissions) {
        if (!needCheckPermission()) {
            return null;
        }
        List<String> deniedPermissions = new ArrayList<>();
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                deniedPermissions.add(permission);
            }
        }
        if (!deniedPermissions.isEmpty()) {
            return deniedPermissions;
        }

        return null;
    }

    /**
     * 是否拥有权限
     */
    public static boolean hasPermissons(@NonNull Activity activity, @NonNull String... permissions) {
        if (!needCheckPermission()) {
            return true;
        }
        for (String permission : permissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }
        return true;
    }

    /**
     * 是否拒绝了再次申请权限的请求(点击了不再询问)
     */
    public static boolean deniedRequestPermissonsAgain(@NonNull Activity activity, @NonNull String... permissions) {
        if (!needCheckPermission()) {
            return false;
        }
        List<String> deniedPermissions = getDeniedPermissions(activity, permissions);
        for (String permission : deniedPermissions) {
            if (ContextCompat.checkSelfPermission(activity, permission) != PackageManager.PERMISSION_DENIED) {

                if (!ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
                    //当用户之前已经请求过该权限并且拒绝了授权这个方法返回true
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 打开app详细设置界面<br/>
     * <p>
     * 在 onActivityResult() 中没有必要对 resultCode 进行判断,因为用户只能通过返回键才能回到我们的 App 中,<br/>
     * 所以 resultCode 总是为 RESULT_CANCEL,所以不能根据返回码进行判断。<br/>
     * 在 onActivityResult() 中还需要对权限进行判断,因为用户有可能没有授权就返回了!<br/>
     */
    public static void startApplicationDetailsSettings(@NonNull Activity activity, int requestCode) {
        Toast.makeText(activity, "点击权限,并打开全部权限", Toast.LENGTH_SHORT).show();

        Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
        Uri uri = Uri.fromParts("package", activity.getPackageName(), null);
        intent.setData(uri);
        activity.startActivityForResult(intent, requestCode);


    }

    /**
     * 申请权限<br/>
     * 使用onRequestPermissionsResult方法,实现回调结果或者自己普通处理
     *
     * @return 是否已经获取权限
     */
    public static boolean requestPerssions(Activity activity, int requestCode, String... permissions) {

        if (!needCheckPermission()) {
            return true;
        }

        if (!hasPermissons(activity, permissions)) {
            if (deniedRequestPermissonsAgain(activity, permissions)) {
                startApplicationDetailsSettings(activity, requestCode);
                //返回结果onActivityResult
            } else {
                List<String> deniedPermissions = getDeniedPermissions(activity, permissions);
                if (deniedPermissions != null) {
                    ActivityCompat.requestPermissions(activity, deniedPermissions.toArray(new String[deniedPermissions.size()]), requestCode);
                    //返回结果onRequestPermissionsResult
                }
            }
            return false;
        }
        return true;
    }

    /**
     * 申请权限返回方法
     */
    public static void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                                  @NonNull int[] grantResults, @NonNull OnRequestPermissionsResultCallbacks callBack) {
        // Make a collection of granted and denied permissions from the request.
        List<String> granted = new ArrayList<>();
        List<String> denied = new ArrayList<>();
        for (int i = 0; i < permissions.length; i++) {
            String perm = permissions[i];
            if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
                granted.add(perm);
            } else {
                denied.add(perm);
            }
        }

        if (null != callBack) {
            if (!granted.isEmpty()) {
                callBack.onPermissionsGranted(requestCode, granted, denied.isEmpty());
            }
            if (!denied.isEmpty()) {
                callBack.onPermissionsDenied(requestCode, denied, granted.isEmpty());
            }
        }


    }


    /**
     * 申请权限返回
     */
//    public interface OnRequestPermissionsResultCallbacks extends ActivityCompat.OnRequestPermissionsResultCallback {
    public interface OnRequestPermissionsResultCallbacks {

        /**
         * @param isAllGranted 是否全部同意
         */
        void onPermissionsGranted(int requestCode, List<String> perms, boolean isAllGranted);

        /**
         * @param isAllDenied 是否全部拒绝
         */
        void onPermissionsDenied(int requestCode, List<String> perms, boolean isAllDenied);

    }
}

主要功能代码实现

public class MainActivity extends AppCompatActivity{
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
    }
    @Override
    protected void initData() {
        requestCameraPermisson();//动态权限申请
        GetPresenter getPresenter = new GetPresenter();
        getPresenter.getData(VersionUpdateBean.class, VERSION_UPDATE);
        getPresenter.attachView(new DataView<VersionUpdateBean>() {
        @Override
        public void callBackData(VersionUpdateBean value) {
            if (!APKVersionCodeUtils.getVerName(mContext).equals(value.getData().getVersion())) {//判断版本号
                forceUpdate(mContext,"应用名称",DOWNLOAD_APK,value.getMsg());
               }
    }

    @Override
    public void callBackDataError(Throwable throwable) {

    }
    });
}
    /**
     * 版本更新
     *
     * @param context
     * @param appName
     * @param downUrl
     * @param updateinfo 更新内容
     */
    private void forceUpdate(final Context context, final String appName, final String downUrl, final String updateinfo) {
        mDialog = new AlertDialog.Builder(context);
        mDialog.setTitle(appName + "版本更新!");
        mDialog.setMessage(updateinfo);
        requestCameraPermisson();
        mDialog.setPositiveButton("立即更新", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            AppInnerDownLoder.downLoadApk(mContext, downUrl, appName);
        }
        }).setCancelable(false).create().show();
    }
    /**
     * 权限获取
     */
    private final int REQUEST_CODE_CAMERA = 101;

    public void requestCameraPermisson() {
        PermissionUtil.requestPerssions(this, REQUEST_CODE_CAMERA,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.READ_SMS,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.READ_EXTERNAL_STORAGE);
        PermissionUtil.getCameraPermissions(this, REQUEST_CODE_CAMERA);
    }

    /**
     * 权限获取
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        PermissionUtil.onRequestPermissionsResult(requestCode, permissions, grantResults, new PermissionUtil.OnRequestPermissionsResultCallbacks() {
            @Override
            public void onPermissionsGranted(int requestCode, List<String> perms, boolean isAllGranted) {
                Log.e(Constant.TAG, "同意:" + perms.size() + "个权限,isAllGranted=" + isAllGranted);
                for (String perm : perms) {
                    Log.e(Constant.TAG, "同意:" + perm);
                }
            }

        @Override
        public void onPermissionsDenied(int requestCode, List<String> perms, boolean isAllDenied) {
            Log.e(Constant.TAG, "拒绝:" + perms.size() + "个权限,isAllDenied=" + isAllDenied);
            for (String perm : perms) {
                Log.e(Constant.TAG, "拒绝:" + perm);
            }
        }
    });
}
}
我的动态权限里有的为获取位置信息,删掉即可


猜你喜欢

转载自blog.csdn.net/peotry_favour/article/details/80497000