App实现自动更新

app上线之后会经常面临版本更新,因此每当有新版本发布时,应用自动更新就显得很有必要!其实整个实现并不复杂,通过后台返回的url,利用Httpurl去下载即可,同时在通知栏显示下载进度.当下载完成时,自动跳转至安装页面.

首先仍然是我代码的目录结构
这里写图片描述


/**事件的监听回调
 * Created by Administrator on 2017/8/14.
 */

public interface UpdateDownloadListener {

    //下载请求开始回调
    public void onStarted();

    //进度更新回调
    public void onProgressChanged(int progress,String downloadUrl);

    //下载完成回调
    public void onFinished(int completeSize,String downloadUrl);

    //下载失败回调
    public void onFailure();

}

/**真正的负责处理文件的下载和线程间的通信
 * Created by Administrator on 2017/8/14.
 */

public class UpdateDownloadRequest implements Runnable{

    private String downloadUrl;
    private String localFilePath;
    private UpdateDownloadListener downloadListener;
    //下载的标记位
    private boolean isDownloading=false;
    //文件长度
    private long currentLength;

    private DownloadResponseHandler downloadHandler;

    public UpdateDownloadRequest(String downloadUrl,String localFilePath,UpdateDownloadListener downloadListener) {
        this.downloadUrl=downloadUrl;
        this.localFilePath=localFilePath;
        this.downloadListener=downloadListener;
        //构造方法完成则开始下载
        this.isDownloading=true;
        this.downloadHandler=new DownloadResponseHandler();
    }

    //真正的去建立连接的方法
    private void makeRequest() throws IOException,InterruptedException
    {
        try {
            if (!Thread.currentThread().isInterrupted())
            {
                URL url = new URL(downloadUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setConnectTimeout(5000);
                //默认也是如此,重新设置避免关闭
                connection.setRequestProperty("Connection","Keep-Alive");
                connection.connect();
                currentLength = connection.getContentLength();
                if (!Thread.currentThread().isInterrupted())
                {
                    //真正完成文件的下载
                    downloadHandler.sendResponseMessage(connection.getInputStream());
                }
            }
        }catch (IOException e){
            throw e;
        }

    }

    @Override
    public void run() {

        try{
            makeRequest();
        }
        catch (IOException e){

        }catch (InterruptedException e){

        }

    }

    //格式化数据,保留两位小数
    private String getTwoPointFloatStr(float value)
    {
        DecimalFormat format = new DecimalFormat("0.00");
        return format.format(value);
    }

    //包含了下载过程中所有可能出现的异常情况
    public enum FailureCode{
        UnknowHost,Socket,SocketTimeout,ConnectTimeout,IO,HttpResponse,JSON,Interrupted
    }

    //用来真正的去下载文件,并发送消息和回调接口
    public class DownloadResponseHandler{

        protected static final int SUCCESS_MESSAGE=0;
        protected static final int FAILURE_MESSAGE=1;
        protected static final int START_MESSAGE=2;
        protected static final int FINISH_MESSAGE=3;
        protected static final int NETWORK_OFF=4;
        protected static final int PROGRESS_CHANGED=5;

        private int mCompleteSize=0;
        private int progress=0;
        private int preProgress=0;

        //真正的完成线程间的通信
        private Handler handler;

        public DownloadResponseHandler() {
            //依附于主线程
            handler=new Handler(Looper.getMainLooper()){
                @Override
                public void handleMessage(Message msg) {
                    super.handleMessage(msg);
                    handleSelfMessage(msg);
                }
            };
        }

        //用来发送不同的消息对象
        protected void sendFinishMessage()
        {
            sendMessage(obtainMessage(FINISH_MESSAGE,null));
        }

        private void sendProgressChangedMessage(int progress)
        {
            sendMessage(obtainMessage(PROGRESS_CHANGED,new Object[]{progress}));
        }

        protected void sendFailureMessage(FailureCode failureCode)
        {
            sendMessage(obtainMessage(FAILURE_MESSAGE,new Object[]{failureCode}));
        }

        protected void sendMessage(Message msg)
        {
            if (handler!=null)
            {
                handler.sendMessage(msg);
            }
            else
            {
                handleSelfMessage(msg);
            }
        }

        //获取一个消息对象
        protected Message obtainMessage(int responseMessage,Object response)
        {
            Message msg=null;
            if (handler!=null)
            {
                msg=handler.obtainMessage(responseMessage,response);
            }
            else
            {
                msg=Message.obtain();
                msg.what=responseMessage;
                msg.obj=response;
            }
            return msg;
        }

        protected void handleSelfMessage(Message msg)
        {
            Object[] response;
            switch (msg.what)
            {
                case FAILURE_MESSAGE:
                    response= (Object[]) msg.obj;
                    handleFailureMessage((FailureCode)response[0]);
                    break;
                case PROGRESS_CHANGED:
                    response= (Object[]) msg.obj;
                    handleProgressChangedMessage(((Integer)response[0]).intValue());
                    break;
                case FINISH_MESSAGE:
                    onFinish();
                    break;
                default:
                    break;
            }
        }

        //各种消息的处理逻辑
        protected void handleProgressChangedMessage(int progress)
        {
            downloadListener.onProgressChanged(progress,"");
        }

        protected void handleFailureMessage(FailureCode failureCode)
        {
            onFailure(failureCode);
        }

        //外部接口的回调
        public void onFinish()
        {
            downloadListener.onFinished(mCompleteSize,"");
        }

        public void onFailure(FailureCode failureCode)
        {
            downloadListener.onFailure();
        }

        //文件下载方法,会发送各种类型的事件,比如下载开始,下载结束,更新进度条等
        void sendResponseMessage(InputStream inputStream)
        {
            RandomAccessFile randomAccessFile=null;
            //记录下载进度
            mCompleteSize=0;
            try{
                byte[] buff = new byte[1024];
                int length=-1;
                int limit=0;
                randomAccessFile=new RandomAccessFile(localFilePath,"rwd");
                while ((length=inputStream.read(buff))!=-1)
                {
                    if (isDownloading)
                    {
                        randomAccessFile.write(buff,0,length);
                        mCompleteSize+=length;
                        if (mCompleteSize<=currentLength)
                        {
                            progress= (int) (mCompleteSize*1.0f/currentLength*100);
                            if (progress>=99||(limit%30==0&&progress<=100))
                            {
                                Log.e("======","====progress===="+progress);
                                /*if (preProgress!=progress)
                                {*/
                                    sendProgressChangedMessage(progress);
                                /*}*/
                            }
                            limit++;
                            preProgress=progress;
                        }
                    }
                }
                sendFinishMessage();
            }catch (IOException e){
                //异常时发送消息
                sendFailureMessage(FailureCode.IO);
            }
            finally {
                try {
                    if (inputStream!=null)
                    {
                        inputStream.close();
                    }
                    if (randomAccessFile!=null)
                    {
                        randomAccessFile.close();
                    }
                }catch (IOException e)
                {
                    sendFailureMessage(FailureCode.IO);
                }

            }
        }
    }
}

/**下载调度管理器,调用我们的updateDownloadRequest
 * Created by Administrator on 2017/8/14.
 */

public class UpdateManager {

    private static UpdateManager manager;
    private ThreadPoolExecutor threadPoolExecutor;
    private UpdateDownloadRequest request;

    public UpdateManager() {
        threadPoolExecutor= (ThreadPoolExecutor) Executors.newCachedThreadPool();
    }

    public static UpdateManager getInstance()
    {
        if (manager==null)
        {
            manager=new UpdateManager();
        }
        return manager;
    }

    public void startDownloads(String downloadUrl,String localPath,UpdateDownloadListener listener)
    {
        if (request!=null)
        {
            return;
        }
        checkLocalFilePath(localPath);
        request=new UpdateDownloadRequest(downloadUrl,localPath,listener);
        threadPoolExecutor.submit(request);
    }

    //检查本地文件路径
    private void checkLocalFilePath(String localPath) {
        File dir = new File(localPath.substring(0, localPath.lastIndexOf("/") + 1));
        if (!dir.exists())
        {
            dir.mkdirs();
        }
        File file = new File(localPath);
        if (!file.exists())
        {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

/**app更新下载后台服务
 * Created by Administrator on 2017/8/14.
 */

public class UpdateService extends Service{

    private String apkUrl;
    private String filePath;
    private NotificationManager notificationManager;
    private Notification notification;

    @Override
    public void onCreate() {
        super.onCreate();
        notificationManager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        filePath= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+
                            File.separator+"autoupdate"+File.separator+"auto.apk";

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent==null)
        {
            notifyUser("下载失败","下载地址错误",0);
            stopSelf();
        }
        else
        {
            apkUrl=intent.getStringExtra("apkUrl");
            notifyUser("开始下载","开始下载",0);
            startDownload();
        }
        return super.onStartCommand(intent, flags, startId);
    }

    private void startDownload() {
        UpdateManager.getInstance().startDownloads(apkUrl, filePath, new UpdateDownloadListener() {

            @Override
            public void onStarted() {

            }

            @Override
            public void onProgressChanged(int progress, String downloadUrl) {
                notifyUser("正在下载","正在下载",progress);
            }

            @Override
            public void onFinished(int completeSize, String downloadUrl) {
                notifyUser("下载完成","下载完成",100);
                stopSelf();
            }

            @Override
            public void onFailure() {
                notifyUser("下载失败","下载失败",0);
                stopSelf();
            }
        });
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    //更新我们的notification来告知用户当前下载的进度
    private void notifyUser(String result, String reason,int progress) {
        NotificationCompat.Builder builder=new NotificationCompat.Builder(this);
        builder.setSmallIcon(R.mipmap.logol)
                .setLargeIcon(BitmapFactory.decodeResource(getResources(),R.mipmap.logol))
                .setContentTitle("autoupdate");
        //Log.e("===progress===","======"+progress);
        if (progress>0&&progress<100)
        {
            builder.setProgress(100,progress,false);
        }
        else
        {
            builder.setProgress(0,0,false);
        }
        builder.setAutoCancel(true);
        builder.setWhen(System.currentTimeMillis());
        builder.setTicker(result);
        if (progress>=100)
        {
            getContentIntent();
        }
        else
        {
            /*builder.setContentIntent(progress>=100?getContentIntent():
                    PendingIntent.getActivity(this,0,new Intent(),PendingIntent.FLAG_UPDATE_CURRENT));*/
            builder.setContentIntent(PendingIntent.getActivity(this,0,new Intent(),PendingIntent.FLAG_UPDATE_CURRENT));
            notification=builder.build();
            notificationManager.notify(0,notification);
        }
    }

    private PendingIntent getContentIntent() {
        //创建一个开启安装App界面的意图
        File apkFile = new File(filePath);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        //判断版本是否在7.0以上
        if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
        {
            Uri apkUri = FileProvider.getUriForFile(this, "com.example.administrator.myautoupdate" +
                            ".fileprovider", apkFile);
            //添加这一句表示对目标应用临时授权该uri所代表的文件
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.setDataAndType(apkUri,"application/vnd.android.package-archive");
        }
        else
        {
            intent.setDataAndType(Uri.parse("file://"+apkFile.getAbsolutePath()),"application/vnd.android.package-archive");
            //intent.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
        }
        startActivity(intent);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
        return pendingIntent;
    }
}

public class MainActivity extends AppCompatActivity {

    Button button_bt;

    String url="http://wap.sogou.com/app/redir.jsp?appdown=1&u=0Gd8piB6093-W-QPHXpNcQJvLH6U5CYd9F0_TSI0vGQYAGh2YbdCmC1hNfN-kHhp&docid=2355133373028692437&sourceid=-5321678202930570851&w=1906&stamp=20170814";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button_bt= (Button) findViewById(R.id.button_bt);

        button_bt.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                checkVersion();
            }
        });
        checkVersion();
    }

    private void checkVersion() {
        CommonDialog dialog = new CommonDialog(this);
        dialog.setListener(new CommonDialog.CommonDialogListener() {

            @Override
            public void confirm() {
                Intent intent = new Intent(MainActivity.this, UpdateService.class);
                intent.putExtra("apkUrl",url);
                startService(intent);
            }
        });

        dialog.show();
    }
}

虽然代码不复杂,但还是得敲过才知道!

程序运行时,界面效果如下
这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值