APP自动更新

作为一个开发的小白,在学习课程以及网上各种找资料实现自动更新,在此记录一下(:з」∠)

  • 在主页面显示更新进度
  • 在通知栏显示更新进度

1.打开APP立即检查更新,在主页面显示更新进度。

在进入Mainactivity时检查APP版本号和后台版本号是否匹配,不匹配则弹出对话框。

具体为下:
在子线程进行获取后台APP的版本号以及更新信息的操作,后台的大佬传的xml文件:

public class UpdateApkThread extends Thread {

    private Context context;
    private Handler handler;

    public UpdateApkThread(Context context, Handler handler) {
        super();
        this.context = context;
        this.handler = handler;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        super.run();

        try {
            URL url = new URL(Bean.UPDATE_APK);  
            HttpURLConnection conn =  (HttpURLConnection) url.openConnection();
            conn.setConnectTimeout(5000);
            InputStream is = conn.getInputStream();
            if (200 == conn.getResponseCode()) {
                String versionCode = "";
                String download= "";
                String content = "";

                XmlPullParser parser = Xml.newPullParser();
                parser.setInput(is, "utf-8");
                int type = parser.getEventType();

                Map<String, String> map = new HashMap<String, String>();

                while(type != XmlPullParser.END_DOCUMENT){  
                    switch (type) {  
                    case XmlPullParser.START_TAG:  
                        if("versioncode".equals(parser.getName())){
                            versionCode = parser.nextText(); //获取版本号  
                        } else if ("download".equals(parser.getName())) {
                            download = parser.nextText();   //获取下载地址
                            map.put("download", download);
                        } else if ("content".equals(parser.getName())) {
                            content = parser.nextText();
                            map.put("content", content);
                        }
                        break;  
                    }  
                    type = parser.next();  
                }  
                Log.e("xml文件", versionCode + "  " + download);

                if (Integer.valueOf(versionCode) > getVersionCode()) {  
                    Log.i("", "版本号不同,提示用户升级 ");
                    Message msg = new Message();
                    msg.what = Bean.UPDATE_SUCCESS;
                    msg.obj = map;
                    handler.sendMessage(msg);
                } else {
                    Log.i("", "版本号相同无需升级");
                }
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }

    /**
     * 获取当前程序的版本号
     * @return
     * @throws NameNotFoundException
     */
    private int getVersionCode() throws NameNotFoundException {
        // 获得已安装的应用程序信息 。可以通过getPackageManager()方法获得
        PackageManager packageManager = context.getPackageManager();
        //getPackageName()是当前类的包名,0代表是获取版本信息
        PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
        return packageInfo.versionCode;
    }  

}

Mainactivity中获取子线程中服务器传来的APP下载地址以及更新信息。

private Handler handler = new Handler() {
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case Bean.UPDATE_SUCCESS:
                Map<String, String> map = (Map<String, String>) msg.obj;
                url = map.get("download");
                message = map.get("message");
                showUpdateDialog();
                Log.e("更新地址和更新内容", url + message);
                break;
            default:
                break;
            }
        };
    };
new UpdateApkThread(MainActivity.this, handler).start();
protected void showUpdateDialog() {
        // TODO Auto-generated method stub
        CustomDialog.Builder builer = new CustomDialog.Builder(this) ;   
        builer.setTitle("版本升级");
        //当点确定按钮时从服务器上下载 新的apk然后安装 
        builer.setMessage(message);
        builer.setPositiveButton("确定", new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int which) {  
                Log.i("", "下载apk,更新");  
                downLoadApk();  
            }     
        });  
        builer.setNegativeButton("取消", new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int which) {  
                // TODO Auto-generated method stub  
                dialog.dismiss();  
            }  
        });  
        builer.create().show();
    }
    /* 
     * 从服务器中下载APK 
     */  
    protected void downLoadApk() {  
        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 = DownloadApk.getFileFromServer(url, pd);  
                    sleep(3000);  
                    installApk(file);  
                    pd.dismiss(); 
                } catch (Exception e) {  
                    Message msg = new Message();  
                    msg.what = 0;  
                    handler.sendMessage(msg);  
                    e.printStackTrace();  
                }  
            }}.start();  
    }
    //安装apk   
    protected void installApk(File file) {  
        Intent intent = new Intent();   
        intent.setAction(Intent.ACTION_VIEW);  
        //执行的数据类型
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");  
        startActivity(intent);  
    }
public class DownloadApk {
    public static 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());  
            InputStream is = conn.getInputStream(); 
            String filePath = Environment.getExternalStorageDirectory() + "/***/*****.apk";
            checkLocalPath(filePath);
            File file = new File(filePath);  
            FileOutputStream fos = new FileOutputStream(file);  
            BufferedInputStream bis = new BufferedInputStream(is);  
            byte[] buffer = new byte[1024];  
            int len ;  
            int progress = 0;  
            while((len = bis.read(buffer)) != -1){  
                fos.write(buffer, 0, len);  
                progress += len;  
                //获取当前下载量  
                pd.setProgress(progress);  
            }  
            fos.close();  
            bis.close();  
            is.close();  
            return file;  
        }  
        else{  
            return null;  
        }  
    }
    private void checkLocalPath(String localFilePath) {
        // TODO Auto-generated method stub
        File dir = new File(localFilePath.substring(0, localFilePath.lastIndexOf("/")));
        Log.e("", ""+localFilePath.substring(0, localFilePath.lastIndexOf("/")));
        if (! dir.exists()) {
            dir.mkdir();
            if (dir.mkdir()) {
                Log.e("目录", "创建目录成功");
            }
        }
        File file = new File(localFilePath);
        if (! file.exists()) {
            try {
                file.createNewFile();
                if (file.createNewFile()) {
                    Log.e("apk文件", "创建文件成功");                   
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

在网上学习的更新,在主页显示缺点是用户在进行更新时不能进行其他操作,所以最好在通知栏显示更新进度。

2.打开APP立即检查更新,在通知栏显示更新进度。在慕课网学习的使用了线程池等,代码有点多,我没有使用线程池,仅结合其它简化了一下,有优化的部分期待指正。

获取后台APP的版本号以及更新信息的操作同上。

在对话框确定时启动服务:

    protected void showUpdateDialog() {
        // TODO Auto-generated method stub
        CustomDialog.Builder builer = new CustomDialog.Builder(this) ;   
        builer.setTitle("版本升级");
        //当点确定按钮时从服务器上下载 新的apk然后安装 
        builer.setMessage(message);
        builer.setPositiveButton("确定", new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int which) {  
                Log.i("", "下载apk,更新");
                Intent intentDownload = new Intent(MainActivity.this, DownloadService.class);
                intentDownload.putExtra("apkUrl", url);
                startService(intentDownload);
                dialog.dismiss();
            }     
        });  
        builer.setNegativeButton("取消", new DialogInterface.OnClickListener() {  
            public void onClick(DialogInterface dialog, int which) {  
                // TODO Auto-generated method stub  
                dialog.dismiss();  
            }  
        });  
        builer.create().show();
    }

启动服务,在服务中设置通知栏(下载中的通知栏时自定义的就不贴布局了),建立子线程进行进度的接收,更新通知。

public class DownloadService extends Service {

    private NotificationManager manager;
    private Notification notification;
    private String apkUrl;
    private String filePath;
    private int progress;
    private RemoteViews view;
    private Handler handler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case 888:
                createNotification("下载完成", progress);
                stopSelf();
                break;

            default:
                stopSelf();
                break;
            }
        };
    };

    @Override
    public void onCreate() {
        // TODO Auto-generated method stub
        manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        filePath = Environment.getExternalStorageDirectory() + "/***/*****.apk";
        checkLocalPath(filePath);
        super.onCreate();
    }

    private void checkLocalPath(String localFilePath) {
        // TODO Auto-generated method stub
        File dir = new File(localFilePath.substring(0, localFilePath.lastIndexOf("/")));
        Log.e("", ""+localFilePath.substring(0, localFilePath.lastIndexOf("/")));
        if (! dir.exists()) {
            dir.mkdir();
            if (dir.mkdir()) {
                Log.e("目录", "创建目录成功");
            }
        }
        File file = new File(localFilePath);
        if (! file.exists()) {
            try {
                file.createNewFile();
                if (file.createNewFile()) {
                    Log.e("apk文件", "创建文件成功");                   
                }
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // TODO Auto-generated method stub
        if (intent == null) {
            createNotification("下载失败", 0);
            stopSelf();
        }
        apkUrl = intent.getStringExtra("apkUrl");
        createNotification("开始下载", 0);
        startDownload();
        return super.onStartCommand(intent, flags, startId);
    }
    private void startDownload() {
        // TODO Auto-generated method stub
        new DownloadApkThread().start();
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }
    private void createNotification(String result, int progress) {
        NotificationCompat.Builder build = new NotificationCompat.Builder(this);
        build.setSmallIcon(R.drawable.ic_launcher)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))
                .setContentTitle(getString(R.string.app_name))
                .setContentText(result);
        build.setAutoCancel(false);
        build.setWhen(System.currentTimeMillis());
        build.setTicker(result);
        build.setContentIntent(progress >= 100 ? getContentIntent() : PendingIntent.getActivity(this, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT));
        notification = build.build();

        if (progress < 100) {           
            //自定义notification
            view = new RemoteViews(getPackageName(), R.layout.notification_update);
            view.setTextViewText(R.id.noti_title, getString(R.string.app_name) + result);
            view.setTextViewText(R.id.noti_percent, "0%");
            view.setProgressBar(R.id.noti_progress, 100, 0, false);
            notification.contentView = view;
        } 
        manager.notify(R.layout.notification_update, notification);
    }

    public PendingIntent getContentIntent() {

        File apkFile = new File(filePath);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.parse("file://" + apkFile.getAbsolutePath()), "application/vnd.android.package-archive");
        return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

    class DownloadApkThread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            super.run();
            int totalSize;// 文件总大小
            int downloadCount = 0;// 已经下载好的大小
            int limit = 0;  //限制一下notification的更新频率
            //如果相等的话表示当前的sdcard挂载在手机上并且是可用的
            if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){  
                URL url = null;
                FileOutputStream fos = null;
                BufferedInputStream bis = null;
                try {
                    url = new URL(apkUrl);
                    HttpURLConnection conn =  (HttpURLConnection) url.openConnection();  
                    conn.setConnectTimeout(5000);  
                    //获取到文件的大小   
                    totalSize = conn.getContentLength();  
                    fos = new FileOutputStream(filePath); 
                    bis = new BufferedInputStream(conn.getInputStream()); 

                    byte[] buffer = new byte[1024];  
                    int len = -1;
                    while((len = bis.read(buffer)) != -1){  
                        fos.write(buffer, 0, len);  
                        downloadCount += len; 
                        Message msg = new Message();
                        if (downloadCount <= totalSize) {
                            progress = (int) (downloadCount * 100 / totalSize);
                            if (limit % 30 == 0 && progress < 100) {
                                //createNotification("正在下载", progress);
                                Log.e("Aa", progress+"");
                                view.setTextViewText(R.id.noti_percent, progress + "%");
                                view.setTextViewText(R.id.noti_title, getString(R.string.app_name) + "正在下载");
                                view.setProgressBar(R.id.noti_progress, 100, progress, false);
                                notification.contentView = view;
                                manager.notify(R.layout.notification_update, notification);
                            }
                            if (progress >= 100) {
                                msg.what = 888;
                                handler.sendMessage(msg);
                            }
                        }
                        limit++;
                    }
                } catch (MalformedURLException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } finally {

                    try {
                        fos.close();  
                        bis.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            }  
        }
    }
}

注意:Android6.0由于对手机安全的优化,需要动态申请读写权限

    // Android 6.0 后需要动态申请读写权限
    private static final int REQUEST_EXTERNAL_STORAGE = 1;
    private static String[] PERMISSIONS_STORAGE = {
            "android.permission.READ_EXTERNAL_STORAGE",
            "android.permission.WRITE_EXTERNAL_STORAGE"};
    public static void verifyStoragePermissions(Activity activity) {

        try {
            //检测是否有写的权限
            int permission = ActivityCompat.checkSelfPermission(activity,
                    "android.permission.WRITE_EXTERNAL_STORAGE");
            if (permission != PackageManager.PERMISSION_GRANTED) {
                // 没有写的权限,去申请写的权限,会弹出对话框
                ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

学习的大概就是以上,记录记录。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值