2016-03-12 15:13:00 honeysx 阅读数 2753
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    22278 人正在学习 去看看 任苹蜻

1、数据库升级概念

在开发应用时,我们经常会用数据库来保存数据。 但是随着应用的版本不断升级, 之前的数据库结构可能不太适应当前版本, 这时就需要升级数据库, 使之符合当前需求。类似应用升级, 数据库的升级也需要version来标明。 不同的是应用版本的升级, 只需更改AndroidManifest.xml文件中的versionCode与versionName即可。 但是数据库的升级需要在代码里面修改。

2、数据库升级原理

2.1、升级原理分析

在使用数据库时, 我们会定义一个扩展了抽象类SQLiteOpenHelper的子类。例如,

图1

图1 DatabaseHelper

其中, 构造函数调用了父类即SQLiteOpenHelper的构造方法, 其中包含了一个version的参数。这个参数即是数据库的版本。 所以,我们可以通过修改version来实现数据库的升级。 一般的,在数据库初始开发时设置为1,然后每次升级时递增。
其次,在SQLiteOpenHelper中还定义了两个抽象的方法,onCreate( )、onUpgrade( )。
这两个方法顾名知义对应着数据库的创建和升级两个过程。我们一般在onCreate( )方法中进行创建表等操作,在onUpgrade( )方法中进行修改表等操作。 例如,

图2

图2 实现的方法

当在某个应用1.0版时, 设置构造方法中的参数version为1。我们在使用SQLiteOpenHelper访问数据库时,系统会读取该参数。如果该参数为0,表示之前没有数据库文件, 则将version为1写入数据库,并调用onCreate( )方法创建数据库。当需要升级数据库时将version设置为2。在应用访问数据库时就会去读取数据库中存储的数据库版本,如果发现不一样(变大), 则会调用onUpgrade( )方法,触发升级逻辑。

2.2、具体代码分析

2.2.1、SQLiteOpenHelper类构造方法

图3

图3 SQLiteOpenHelper构造方法

其中, CursorFactory和DatabaseErrorHandler一般是传null。 我们可以看到,构造SQLiteOpenHelper对象时如果数据库版本号低于1是会报异常的。

2.2.2、SQLiteOpenHelper的使用

在访问数据库时,我们一般会new一个SQLiteHelper的对象。

图4

图4 SQLiteOpenHelper的使用

其中,getWritableDatabase( )会调用getDatabaseLocked(false)方法,在该方法中实现了对数据库版本检查和升级等的逻辑。其中部分代码如下,

图5

图5 数据库升级逻辑

我们可以看到,系统会先调用getVersion( )获取当前数据库版本。如果没有数据库文件存在,则getVersion( )方法会返回0. 从而调用onCreate( )方法。如果version不为0,则会比较当前version与数据库中保存的version值从而决定是升级还是降级。对于降级系统会抛出异常,如下

图6

图6 降级逻辑

而升级的操作,则需要我们在子类中实现。最后,系统会将当前数据库版本version值保存到数据库中。

3、数据库升级注意事项

在升级数据库时,如果我们需要在原有表的基础上增加一个字段,那么需要注意的是,一定要为老数据的的新添字段设置默认值。否则,在查询该数据表时会返回空。增加列并设置默认值的方法如下:

图7

图7 增加字段并设置默认值

其次,数据库的升级是对于升级用户的而言的。但是对于新用户系统会新创建数据库,所以在增加字段的同时也要在onCreate( )方法中修改创建该表的SQL语句,从而增加字段。这样那么不管是升级用户还是新用户,数据库中的该表都增加了该字段。

4、结论

1.数据库的升级是通过修改version值实现的。
2.新用户会通过onCreate()方法产生数据库。对于升级用户而言,如果没有升级数据库,则不会进行数据库创建及升级操作。如果升级了数据库,则会调用onUpgrade( )方法。
3.应用的升级与数据库升级无必然的联系。

5、参考

  1. 网址:http://blog.csdn.net/jiangwei0910410003/article/details/39670813
2016-10-06 14:05:51 yancey_blog 阅读数 4158
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    22278 人正在学习 去看看 任苹蜻

本章将介绍360多渠道打包方法


Android多渠道打包(一):基础多渠道打包
Android多渠道打包(二):友盟多渠道打包
Android多渠道打包(三):美团多渠道打包
Android多渠道打包(四):360多渠道打包
Android多渠道打包(五):360多渠道打包+
Android多渠道打包(六):maven&gradle
Android多渠道打包(七):系列总结及展望


来源

这个打包方法是由奇虎360的工程师开源出来的,这位大神在github的id是seven456

原理

利用的是Zip文件“可以添加comment(摘要)”的数据结构特点,在文件的末尾写入任意数据,而不用重新解压zip文件(apk文件就是zip文件格式);所以该工具不需要对apk文件解压缩和重新签名即可完成多渠道自动打包,高效速度快,无兼容性问题;

实现方式

  • java源码
/*关键代码*/

    public static void main(String[] args) throws Exception {
//      写入渠道号
//      args = "-path D:/111.apk -outdir D:/111/ -contents googleplay;m360; -password 12345678".split(" ");
//      查看工具程序版本号
//      args = "-version".split(" ");
//      读取渠道号
//      args = "-path D:/111_m360.apk -password 12345678".split(" ");

        long time = System.currentTimeMillis();
        String cmdPath  = "-path";
        String cmdOutdir  = "-outdir";
        String cmdContents  = "-contents";
        String cmdPassword  = "-password";
        String cmdVersion  = "-version";
        String help = "用法:java -jar MCPTool.jar [" + cmdPath + "] [arg0] [" + cmdOutdir + "] [arg1] [" + cmdContents + "] [arg2] [" + cmdPassword + "] [arg3]"
                + "\n" + cmdPath + "        APK文件路径"
                + "\n" + cmdOutdir + "      输出路径(可选),默认输出到APK文件同一级目录"
                + "\n" + cmdContents + "    写入内容集合,多个内容之间用“;”分割(linux平台请在“;”前加“\\”转义符),如:googleplay;m360; 当没有" + cmdContents + "”参数时输出已有文件中的contents"
                + "\n" + cmdPassword + "    加密密钥(可选),长度8位以上,如果没有该参数,不加密"
                + "\n" + cmdVersion + " 显示MCPTool版本号"
                + "\n例如:"
                + "\n写入:java -jar MCPTool.jar -path D:/test.apk -outdir ./ -contents googleplay;m360; -password 12345678"
                + "\n读取:java -jar MCPTool.jar -path D:/test.apk -password 12345678";

        if (args.length == 0 || args[0] == null || args[0].trim().length() == 0) {
            System.out.println(help);
        } else {
            if (args.length > 0) {
                if (args.length == 1 && cmdVersion.equals(args[0])) {
                    System.out.println("version: " + VERSION_1_1);
                } else {
                    Map<String, String> argsMap = new LinkedHashMap<String, String>();
                    for (int i = 0; i < args.length; i += 2) {
                        if (i + 1 < args.length) {
                            if (args[i + 1].startsWith("-")) {
                                throw new IllegalStateException("args is error, help: \n" + help);
                            } else {
                                argsMap.put(args[i], args[i + 1]);
                            }
                        }
                    }
                    System.out.println("argsMap = " + argsMap);
                    File path = argsMap.containsKey(cmdPath) ? new File(argsMap.get(cmdPath)) : null;
                    String parent = path == null? null : (path.getParent() == null ? "./" : path.getParent());
                    File outdir = parent == null ? null : new File(argsMap.containsKey(cmdOutdir) ? argsMap.get(cmdOutdir) : parent);
                    String[] contents = argsMap.containsKey(cmdContents) ? argsMap.get(cmdContents).split(";") : null;
                    String password = argsMap.get(cmdPassword);
                    if (path != null) {
                        System.out.println("path: " + path);
                        System.out.println("outdir: " + outdir);
                        if (contents != null && contents.length > 0) {
                            System.out.println("contents: " + Arrays.toString(contents));
                        }
                        System.out.println("password: " + password);
                        if (contents == null || contents.length == 0) { // 读取数据;
                            System.out.println("content: " + readContent(path, password));
                        } else { // 写入数据;
                            String fileName = path.getName();
                            int dot = fileName.lastIndexOf(".");
                            String prefix = fileName.substring(0, dot);
                            String suffix = fileName.substring(dot);
                            for (String content : contents) {
                                File target = new File(outdir, prefix + "_" + content + suffix);
                                if (nioTransferCopy(path, target)) {
                                    write(target, content, password);
                                }
                            }
                        }
                    }
                }
            }
        }
        System.out.println("time:" + (System.currentTimeMillis() - time));
    }
}
  • 使用方法

1、命令行使用说明:
用法:java -jar MCPTool.jar [-path] [arg] [-contents] [arg] [-password] [arg]
-path APK文件路径
-outdir 输出路径(可选),默认输出到APK文件同一目录
-contents 写入内容集合,多个内容之间用“;”分割,如:googleplay;m360; 当没有“-contents”参数时输出已有文件中的content
-password 加密密钥(可选),长度8位以上,如果没有该参数,不加密
-version 显示版本号
例如:

写入:
java -jar MCPTool.jar -path D:/test.apk -outdir ./ -contents googleplay;m360; -password 12345678
读取:
java -jar MCPTool.jar -path D:/test.apk -password 12345678

2、Android代码中读取写入的渠道号:
导入MCPTool.jar中的MCPTool类,MCPTool.getChannelId(context, mcptoolPassword, defValue)读出写入的渠道号;

3、jenkins、hudson、ant使用说明:
请看MultiChannelPackageTool\build-ant\MCPTool\build.xml文件;

4、Windows下bat脚本运行说明:
拖拽文件即可完成多渠道打包:MultiChannelPackageTool\build-ant\MCPTool\MCPTool.bat;
拖拽文件检查渠道号是否写入成功:MultiChannelPackageTool\build-ant\MCPTool\MCPTool-check.bat;

  • 获取渠道号
/**
     * Android平台读取渠道号
     * @param context Android中的android.content.Context对象
     * @param mcptoolPassword mcptool解密密钥
     * @param defValue 读取不到时用该值作为默认值
     * @return
     */
    public static String getChannelId(Object context, String mcptoolPassword, String defValue) {
        String content = MCPTool.readContent(new File(getPackageCodePath(context)), mcptoolPassword);
        return content == null || content.length() == 0 ? defValue : content;
    }
String channelId = MCPTool.getChannelId(context,password,default);

优缺点

没有解压缩、压缩、重签名,没有兼容性问题,速度最快;写入的渠道号数据支持加密,安全可靠;

由于速度极快,我还可以作为服务器端下载apk时动态写入“特定数据”,用户下载到apk后安装启动,读取“特定数据”完成特定的操作;
如:加好友功能,下载前写入用户ID,用户下载后启动apk,读取写入的用户ID,完成加好友操作,用户体验大大提升,没有断裂感;
当然,也可以写入JSON数据,想做什么就做什么;

引用

seven456:MultiChannelPackageTool


2016-09-18 13:42:23 haozhenghui10 阅读数 489
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    22278 人正在学习 去看看 任苹蜻

android完整包升级,包括本地升级和网络升级。
本地升级比较简单,选择升级包后调用系统api RecoverySystem.installPackage函数开始升级。
网络升级主要设计上传更新包和下载更新包。升级方式跟本地升级一样。
如果需要OTA 查分升级,可以研究一下RecoverySystem.installPackage函数。
网络升级还有一个难点就是上传和下载,如果直接用socket上传或者下载的话,由于网络速度太慢,文件包太大,服务器网速限制会非常慢,而且不太稳定。所以我这里采用FTP服务器,上传下载问题。
网络更新包的信息采用mysql数据库保存,用于保存更新包信息。每个更新包都有一个版本号,如果当前系统版本小于数据库保存的版本,就显示升级。

2016-09-26 10:25:51 duanmulirui 阅读数 374
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    22278 人正在学习 去看看 任苹蜻

最近有涉及Android各个渠道,各个市场账号的申请,来做一下总结和记录。

首先,Android应用发行和发布可一键式,可用比如酷传,网址:http://www.coolchuan.com/ ,注册相关渠道后绑定即可。


其中,所用到的各大渠道市场例举一下:

1.QQ应用宝:

http://open.qq.com/

2.豌豆荚:

http://developer.wandoujia.com/

3.360手机助手:

 http://dev.360.cn/

4.应用汇:

http://dev.appchina.com/market/dev/index.action/

5.华为:

http://developer.huawei.com/

6.小米市场:

http://dev.xiaomi.com/console/

7.百度:

http://developer.baidu.com/

(现在,上传Android渠道版本仅注册百度账号,同时会同步发布91助手和安卓市场)

8.PP助手:

http://open.25pp.com/(同淘宝)

9.魅族:

http://developer.meizu.com/



其中,申请各个开发者账号时,如果是企业认证的话,需要提前准备好各种资料等,这样申请比较快些。


AndroidStudio打渠道包:

在AndroidManifest.xml中添加

                <meta-data-->
                 android:name="ID_CHANNEL"
                 android:value="${ID_CHANNEL_VALUE}" />


在app下的build.gradle文件中添加

        productFlavors{

                baidu{}

                huawei{}

              

                 productFlavors.all { flavor ->

                            flavor.mainfestPlaceholders = [ID_CHANNEL_VALUE:name]

                 }

        }

然后,build -> generate signed APK  就可以选择相应的flavor来打包。





2018-05-25 14:31:17 Silence_Sep 阅读数 221
  • 快速入门Android开发 视频 教程 android studio

    这是一门快速入门Android开发课程,顾名思义是让大家能快速入门Android开发。 学完能让你学会如下知识点: Android的发展历程 搭建Java开发环境 搭建Android开发环境 Android Studio基础使用方法 Android Studio创建项目 项目运行到模拟器 项目运行到真实手机 Android中常用控件 排查开发中的错误 Android中请求网络 常用Android开发命令 快速入门Gradle构建系统 项目实战:看美图 常用Android Studio使用技巧 项目签名打包 如何上架市场

    22278 人正在学习 去看看 任苹蜻

 

Android 软件升级:

 

逻辑:1.首先获取本地版本号和服务器版本号,如果服务器版本号大于本地版本号,则需要更新,否则不需要更新。

2. 如果需要更新,那么先查看下本地是否有这个安装包,如果有则直接安装,如果没有则需要网络下载,下载完成时直接安装。(下载的安装包命名:淘宝3.0.2.apk)

3. 那么应该在什么地方更新呢?如图:

应该在①②处判断更新,倘若在①处判断了,则不必在②处判断,倘若是登录状态,则会直接进入main页面,此时需要在②处判断,另外还需要在设置中的软件更新处判断(如果有这个需求)

 

 

 

注意:6.0需要动态获取读取权限。

 

 

package com.skt.itrip.common;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;

import com.skt.itrip.R;
import com.skt.itrip.dialog.DownloadDialog;
import com.zhy.http.okhttp.OkHttpUtils;
import com.zhy.http.okhttp.callback.FileCallBack;

import java.io.File;

import okhttp3.Call;
import okhttp3.Request;

public class UpdateUtils {

    private  static Dialog mDownloadDialog;
    private static SharedPreferences sp;

    /**
     * 版本对比,如果服务器的版本 > 本地版本 ----->升级
     */
    
public static boolean CheckUpdate(Context context,int serverVersionCode, int localVersionCode,String serverVersionName){
        if(serverVersionCode > localVersionCode){
            hasNewVersion(context,true,serverVersionName,serverVersionCode);
           return true;
        }else{
            hasNewVersion(context,false,serverVersionName,serverVersionCode);
            return false;
        }
//        return true;
    
}

    private static  void hasNewVersion(Context context,boolean hasNewVersion,String serverVersionName,int serverVersionCode){
        sp = context.getSharedPreferences(Constant.SP_FILE_NAME, Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putBoolean("hasNewVersion", hasNewVersion);
        editor.putString("serverVersionName", serverVersionName);
        editor.putInt("serverVersionCode", serverVersionCode);
        editor.apply();
    }


    public  static void notNewVersionShow(final Context context, String localVersionName, int localVersionCode) {
        String sb = context.getResources().getString(R.string.current_version) +
                localVersionName +
                " Code:" +
                localVersionCode +
                ",已是最新版,无需更新!";
        Dialog dialog = new android.support.v7.app.AlertDialog.Builder(context).setTitle(context.getResources().getString(R.string.update_software))
                .setMessage(sb)// 设置内容
                
.setPositiveButton(context.getResources().getString(R.string.common_confirm),// 设置确定按钮
                        
new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog,
                                                int which) {
                                dialog.dismiss();
                            }
                        }).create();// 创建
        // 显示对话框
        
dialog.show();
    }
    /**
     * 升级
     */
    
public static void doNewVersionUpdate(final Context context, String localVersionName, int localVersionCode, final String serverVersionName, int serverVersionCode) {
        String sb = context.getResources().getString(R.string.current_version) +
                localVersionName +
                " Code:" +
                localVersionCode +
                ", 发现新版本:" +
                serverVersionName +
                " Code:" +
                serverVersionCode +
                ", 是否更新?";
        Dialog dialog = new AlertDialog.Builder(context)
                .setTitle(context.getResources().getString(R.string.update_software))
                .setMessage(sb)
                .setCancelable(false)
                // 设置内容
                
.setPositiveButton(context.getResources().getString(R.string.update_now),// 设置确定按钮
                        
new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int which) {

                                //先检查本地有没有,如果本地存在,直接安装
                                
if(fileIsExists(getPath(context))){
                                    LOG.e("localFile","path==" + getPath(context));
                                    File file = new File(getPath(context));
                                    install(context,file);
                                }else{//网络下载
                                    mDownloadDialog
= DownloadDialog.createdownloadDialog(context);
                                    DownloadDialog.showDialog(mDownloadDialog);
                                    //执行下载操作

                                    downloadFile
(context,serverVersionName);
                                }
                            }
                        })
                .setNegativeButton(context.getResources().getString(R.string.update_later),
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                                int whichButton) {
                                // 点击"取消"按钮之后退出程序
//                                finish();
                                
dialog.dismiss();
                            }

                        }).create();// 创建
        // 显示对话框
        
dialog.show();
    }



    private static  String getPath(Context context){
        sp = context.getSharedPreferences("skt_demo", Context.MODE_PRIVATE);
        return sp.getString("apkPath","");
    }


    //    下载时给文件命名时带上服务器返回的最新的版本号,然后去查找手机里有无该文件,有就直接安装,否则下载
    //    文件命名可以是应用名+版本号
    
private static boolean fileIsExists(String strFile)
    {
        try
        
{
            File f=new File(strFile);
            if(!f.exists())
            {
                return false;
            }

        }
        catch (Exception e)
        {
            return false;
        }

        return true;
    }


    private  static void downloadFile(final Context context,final String serverVersionName)
    {
        String downLoadUrl = Constant.baseUrl + "AppWebService.do?downloadLocal";
        OkHttpUtils//
                
.get()//
                
.url(downLoadUrl)//
                
.build()//
                
.execute(new FileCallBack(Environment.getExternalStorageDirectory().getAbsolutePath(), context.getString(R.string.app_name) + serverVersionName + ".apk")//
                
{

                    @Override
                    public void onBefore(Request request, int id)
                    {

                    }

                    @Override
                    public void inProgress(float progress, long total, int id)
                    {
                        LOG.e("AlterPasswordModelImpl","inProgress :" + (int) (100 * progress));
                        DownloadDialog.setProgress((int) (100 * progress));

                    }

                    @Override
                    public void onError(Call call, Exception e, int id)
                    {
                        LOG.e("AlterPasswordModelImpl", "onError :" + e.getMessage());
                        DownloadDialog.closeDialog(mDownloadDialog);
                        ShowToast.showToast("下载失败,请检查网络连接",context);
                    }

                    @Override
                    public void onResponse(File file, int id)
                    {
                        LOG.e("localFile", "onResponse :" + file.getAbsolutePath());
//                        /storage/emulated/0/旅行家3.apk
                        saveFilePath
(context,file.getAbsolutePath());
                        DownloadDialog.closeDialog(mDownloadDialog);
                        install(context,file);
                    }
                });
    }

    private static void saveFilePath(Context context,String path){
        sp = context.getSharedPreferences("skt_demo", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = sp.edit();
        editor.putString("apkPath", path);
        editor.apply();
    }


    /**
     * 安装apk
     *
     *
@param context
     
*            Context
     *
@param apkFile
     
*            apk文件
     */
    
private  static void install(Context context, File apkFile) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {// 7.0+
            
uri = FileProvider.getUriForFile(context, "com.skt.itrip.fileprovider", apkFile);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            uri = Uri.fromFile(apkFile);
        }
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

}

 

 

 

调用:

  /**     * 获取版本信息成功的回调     */    

@Override    

public void getServerVersionSuccess(int serverVersionCode,String serverVersionName) {

//  url = "http://www.goodstong.com/apk/hgwl-v1.1.0-beta4.apk";        

this.serverVersionName = serverVersionName;

        this.serverVersionCode = serverVersionCode;

        if(UpdateUtils.CheckUpdate(context,serverVersionCode,localVersionCode,serverVersionName)){//需要更新           checkPermission();

        }

    }

 

/**
 * 动态申请读取权限
 */
private  void checkPermission(){
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//6.0以上
        if(context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED &&
                context.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {

            // 申请一个(或多个)权限,并提供用于回调返回的获取码(用户定义)
            requestPermissions( new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,Manifest.permission.WRITE_EXTERNAL_STORAGE }, CODE_READ_EXTERNAL_STORAGE);

        }else{
            UpdateUtils.doNewVersionUpdate(context,localVersionName,localVersionCode,serverVersionName,serverVersionCode); // 更新新版本
        }
    }else{
        UpdateUtils.doNewVersionUpdate(context,localVersionName,localVersionCode,serverVersionName,serverVersionCode); // 更新新版本
    }
}

/**
 * 动态申请权限的回调
 */
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions,grantResults);
    switch(requestCode) {

        // requestCode即所声明的权限获取码,在checkSelfPermission时传入
        case CODE_READ_EXTERNAL_STORAGE:
            if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 获取到权限,作相应处理(调用定位SDK应当确保相关权限均被授权,否则可能引起定位失败)
                UpdateUtils.doNewVersionUpdate(context,localVersionName,localVersionCode,serverVersionName,serverVersionCode); // 更新新版本
            } else{
                Toast.makeText(context,"没有获取读取手机权限,请到应用中心手动打开该权限",Toast.LENGTH_SHORT).show();
                // 没有获取到权限,做特殊处理
            }
            break;


    }
}

 8.0:

<!-- 用于8.0允许安装未知来源的apk -->

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

 

7.0:manifest.xml

 

<provider
    android:name="android.support.v4.content.FileProvider"
    android:authorities="com.skt.itrip.fileprovider"
    android:exported="false"
    android:grantUriPermissions="true">
    <meta-data
        android:name="android.support.FILE_PROVIDER_PATHS"
        android:resource="@xml/file_paths" />
</provider>

file_paths.xml:

 

<?xml version="1.0" encoding="utf-8"?>
<resource  xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="name" path="" />
    <!--<cache-path name="name" path="path" />-->
</resource >

.java

private  static void install(Context context, File apkFile) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        Uri uri;
        if (Build.VERSION.SDK_INT >= 24) {// 7.0+
            
uri = FileProvider.getUriForFile(context, "com.skt.itrip.fileprovider", apkFile);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            uri = Uri.fromFile(apkFile);
        }
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }
 

资源:https://download.csdn.net/download/silence_sep/10438031

常用工具类:https://download.csdn.net/download/silence_sep/10438088

软件升级设计图

阅读数 294

Android软件升级逻辑设计图

博文 来自: u011511057

Android之软件升级

阅读数 62

没有更多推荐了,返回首页