App实现自动更新

来源:互联网 发布:无人机遥控软件 编辑:程序博客网 时间:2024/05/29 23:47

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();    }}虽然代码不复杂,但还是得敲过才知道!

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

原创粉丝点击