Android 版本更新解决方案

   最近友盟因为应用商店审核遭拒等原因,十月份停止版本更新服务,所以我们的项目集成的友盟版本更新就糟了秧了...求安慰.然后就只能自己动手丰衣足食喽.
   版本更新说白无非就是在一个远程仓库中存放一个apk文件然后提供一个URL,而我们需要做的无非就是把这个文件下载下来,然后覆盖手机上原来的版本,从而实现了更新.
   整理一下思路,用到的技术有文件下载,存放在本地,监测是否下载完成,提示安装.另外因为dialog会引起莫名的错误,所以所有的弹框全部采用的是dialogfragment.下面几种是我用过的方法.

方法一

public void downFile(final String url) {
    pBar = new ProgressDialog(getContext());    //进度条,在下载的时候实时更新进度
    pBar.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    pBar.setCancelable(false);
    pBar.setTitle("正在下载");
    pBar.setMessage("请稍候...");
    pBar.setProgress(0);
    pBar.show();
    //如果相等的话表示当前的sdcard挂载在手机上并且是可用的
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
        new Thread() {
            public void run() {
                try {
                    URL path = new URL(url);
                    HttpURLConnection conn = (HttpURLConnection) path.openConnection();
                    conn.setConnectTimeout(5000);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

HttpClient client = new DefaultHttpClient();
                HttpGet get = new HttpGet(url);
                HttpResponse response;
                try {
                    response = client.execute(get);
                    HttpEntity entity = response.getEntity();
                    int length = (int)          entity.getContentLength();   //获取文件大小
                    pBar.setMax(length); //设置进度条的总长度                      
                    InputStream is = entity.getContent();
                    FileOutputStream fileOutputStream = null;
                    if (is != null) {
                        File file = new File(
                                Environment.getExternalStorageDirectory(),
                                "huanshoulv.apk");
                        fileOutputStream = new FileOutputStream(file);
                        byte[] buf = new byte[1024];   //缓冲区,即一次读取1024个比特
                        int ch = -1;
                        int process = 0;
                        while ((ch = is.read(buf)) != -1) {
                            fileOutputStream.write(buf, 0, ch);
                            process += ch;
                            pBar.setProgress(process);       //更新进度
                        }
                    }
                    fileOutputStream.flush();
                    if (fileOutputStream != null) {
                        fileOutputStream.close();
                    }
                    update();
                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    } else {
        return;
    }
}

//安装文件
void update() {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setDataAndType(Uri.fromFile(new File(Environment
                    .getExternalStorageDirectory(), "huanshoulv.apk")),
            "application/vnd.android.package-archive");
    PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    builder.setContentTitle("下载完成").setContentText("点击安装").setContentIntent(pendingIntent);
    nf = builder.build();
    nm.notify(0, nf);
    startActivity(intent);
    android.os.Process.killProcess(android.os.Process.myPid());
}

方法二

public class MyDownloadAnsy extends AsyncTask<String, Integer, Integer> {
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        builder = new NotificationCompat.Builder(getContext()).setSmallIcon(R.mipmap.icon_wx).setContentInfo("下载中...").setContentTitle("正在下载");
        nf = builder.build();
    }

    @Override
    protected Integer doInBackground(String... params) {
        HttpURLConnection con = null;
        InputStream is = null;
        OutputStream os = null;
        try {
            String path = params[0];
            MyLog.e("path : " + path);
            URL url = new URL(path);
            con = (HttpURLConnection) url.openConnection();
            con.setConnectTimeout(5 * 1000);  //设置超时时间
            if (con.getResponseCode() == 200) { //判断是否连接成功
                int fileLength = con.getContentLength();
                is = con.getInputStream();    //获取输入
                os = new FileOutputStream("/sdcard/huanshoulv.apk");
                byte[] buffer = new byte[1024 * 1024 * 10];
                long total = 0;
                int count;
                int pro1 = 0;
                int pro2 = 0;
                while ((count = is.read(buffer)) != -1) {
                    total += count;
                    if (fileLength > 0)
                        pro1 = (int) (total * 100 / fileLength);  //传递进度(注意顺序)
                    if (pro1 != pro2)
                        publishProgress(pro2 = pro1);
                    os.write(buffer, 0, count);
                }
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
                if (os != null) {
                    os.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (con != null) {
                con.disconnect();
            }
        }
        return 1;
    }

    @Override
    protected void onPostExecute(Integer result) {
        super.onPostExecute(result);

        if (result == 1) {
            MessagePop.ToastMessage(getContext(), "下载完成");
        }
    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        Log.d("===", "" + values[0]);
        super.onProgressUpdate(values);
        builder.setProgress(100, values[0], false);
        nf = builder.build();
        nm.notify(0, nf);
        if (values[0] == 100) {    //下载完成后点击安装
            Intent it = new Intent(Intent.ACTION_VIEW);
            it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            it.setDataAndType(Uri.parse("file:///sdcard/huanshoulv.apk"), "application/vnd.android.package-archive");
            PendingIntent pendingIntent = PendingIntent.getActivity(getContext(), 0, it, PendingIntent.FLAG_UPDATE_CURRENT);
            builder.setContentTitle("下载完成").setContentText("点击安装").setContentIntent(pendingIntent);
            nf = builder.build();
            nm.notify(0, nf);
        }
    }
}

“`
方法三
上面的两种方式就是最简单文件下载然后监听安装,不过不同手机或许会出现不同的问题,还好谷歌给我们支持了,就是Android系统的DownloadManager ,个人觉得比较方便实用,它可以检测下载速度,显示下载进度,文件大小,断点下载等强大功能,下载过程中他会自动检测网络状态,网络断开时停止下载,连接上时自动接着下载,还可以设置成只有在wifi下面才进行下载,代码里面关键代码都写了注释,比较简单。

private static DownloadManager manager;
private static long downloadId;
private static String DOWNLOAD_FILE_NAME = "update.apk";

    public static void versionUpdate(Context context, String url) {
    manager = (DownloadManager) context.getSystemService(context.DOWNLOAD_SERVICE);
    DownloadManager.Query query = new DownloadManager.Query();
    query.setFilterById(downloadId);
    query.setFilterByStatus(DownloadManager.STATUS_RUNNING);//正在下载
    Cursor c = manager.query(query);
    if (c.moveToNext()) {
        //正在下载中,不得重新下载
        MessagePop.ToastMessage(context, "正在下载中,不得重新下载!");
    } else {
        //创建下载请求
        DownloadManager.Request down = new DownloadManager.Request(Uri.parse(url));
        //设置允许使用的网络类型,这里是移动网络和wifi都可以
      down.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
        //显示在下载界面,即下载后的文件在系统下载管理里显示
        down.setVisibleInDownloadsUi(true);
        //设置下载标题
        down.setTitle("版本更新");
        down.setDescription("APP");
        //显示Notification
        down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        down.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
        //设置下载后文件存放的位置
        down.setDestinationInExternalFilesDir(context, null, DOWNLOAD_FILE_NAME);
//            down.setDestinationInExternalPublicDir("/" + getPackageName() + "/", "update.apk");
        //将下载请求放入队列,返回值为downloadId
        downloadId = manager.enqueue(down);
    }
}

然后写一个dialogfragment来弹出对话框提示你是否升级,

public class DialogFragmentUpdate extends DialogFragment {
private TextView tv_title;
private TextView tv_content;
private TextView tv_cancel;
private TextView tv_confirm;
private View view_line;

public static DialogFragmentUpdate newInstance(AppInfo appInfo) {
    DialogFragmentUpdate instance = new DialogFragmentUpdate();
    Bundle args = new Bundle();
    args.putSerializable("appInfo", appInfo);
    instance.setArguments(args);
    return instance;
}

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
    getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
    final Window dialogWindow = getDialog().getWindow();
    WindowManager.LayoutParams lp = dialogWindow.getAttributes();
    dialogWindow.setGravity(Gravity.CENTER);
    lp.width = DimensionUtil.dip2px(getContext(), 315);
    lp.height = DimensionUtil.dip2px(getContext(), 350);
    dialogWindow.setAttributes(lp);

    View view = inflater.inflate(R.layout.dialogfragment_version_update, null);
    view_line = view.findViewById(R.id.view_line);
    view_line.setVisibility(View.VISIBLE);
    tv_title = (TextView) view.findViewById(R.id.tv_title);
    final AppInfo appInfo = (AppInfo) getArguments().getSerializable("appInfo");
    tv_title.setText("最新版本:" + appInfo.getVersion());
    tv_content = (TextView) view.findViewById(R.id.tv_content);
    tv_content.setText(appInfo.getDescription());
    tv_cancel = (TextView) view.findViewById(R.id.tv_cancel);
    tv_cancel.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dismissAllowingStateLoss();
        }
    });
    tv_confirm = (TextView) view.findViewById(R.id.tv_confirm);
    tv_confirm.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            ConnectivityManager connMgr = (ConnectivityManager) getContext()
                    .getSystemService(getContext().CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = connMgr
                    .getNetworkInfo(ConnectivityManager.TYPE_WIFI);
            boolean isWifiConn = networkInfo.isConnected();
            networkInfo = connMgr.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
            boolean isMobileConn = networkInfo.isConnected();
            if (isWifiConn) {//Wifi
                VersionUtil.versionUpdate(getContext(), appInfo.getUrl());
                MessagePop.ToastMessage(getContext(), getString(R.string.loading_status));
                dismissAllowingStateLoss();
            } else if (isMobileConn) {//流量
                //将当前的Fragment清除,并放入回退栈
                FragmentTransaction ft = getFragmentManager().beginTransaction();
                ft.remove(DialogFragmentUpdate.this);
                ft.addToBackStack(null);
                DialogFragmentPrompt prompt = DialogFragmentPrompt.newInstance(appInfo);
                prompt.show(getFragmentManager(), "prompt");
            } else {//无网络
                MessagePop.ToastMessage(getContext(), getString(R.string.connect_error));
            }
        }
    });
    return view;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setCancelable(true);
}

}
用到的实体类AppInfo.java

public class AppInfo implements Serializable {
private int type;               //类型1-iOS 2-Android
private String description;     //更新描述
private String url;             //下载链接
private String version;         //版本号
private boolean needUpdate;     //标志位 是否需要更新
private boolean force_update;   //强制更新

public static AppInfo getAppInfo(JsonElement jsonElement) {
    Gson gson = new Gson();
    return gson.fromJson(jsonElement, AppInfo.class);
}

public int getType() {
    return type;
}

public String getDescription() {
    return description;
}

public String getUrl() {
    return url;
}

public String getVersion() {
    return version;
}

public boolean isNeedUpdate() {
    return needUpdate;
}

public boolean isForce_update() {
    return force_update;
}

}
接下来就只是引用这个dialogfragment就好了.
另外,我们需要写一个Receiver用来监听文件是否下载完成,完成的话提示安装.

public class APKDownloadCompleteReceiver extends BroadcastReceiver {
private DownloadManager manager;

@Override
public void onReceive(Context context, Intent intent) {
    manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
    if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
        //通过downloadId去查询下载的文件名
        long downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
        Query query = new Query();
        query.setFilterById(downloadId);
        Cursor myDownload = manager.query(query);
        if (myDownload.moveToFirst()) {
            int fileNameIdx = myDownload.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME);
            String fileName = myDownload.getString(fileNameIdx);
            installAPK(fileName, context);
        }
    }
}

//安装APK
private void installAPK(String filePath, Context context) {
    Intent intent = new Intent();
    intent.setAction("android.intent.action.VIEW");
    intent.addCategory("android.intent.category.DEFAULT");
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);//广播里面操作需要加上这句,存在于一个独立的栈里
    intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");
    context.startActivity(intent);
}

}
在Mainfest.xml中配置文件Receiver

    <receiver android:name=".widget.receiver.APKDownloadCompleteReceiver">
        <intent-filter>
            <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
        </intent-filter>
    </receiver>

最后这样就可以了,亲测有效,至于兼容性问题,这是谷歌大大提供的应该不会有问题.

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值