Android下载apk全量更新实现

自从Umeng的更新SDK不能用了之后,公司的Android更新都是自己实现的,于是自己实现了一下,大致流程如下:
1.获取本地版本号;
2.获取服务器的版本号,进行比较,如果服务器的版本号大于本地的版本号,责提示用户进行更新;
3.如果需要更新,就开启一个Service进行版本更新。
代码如下:
1.获取本地版本号:

private String getLocalVersion() {
    try {
      PackageManager manager = this.getPackageManager();
      PackageInfo info = manager.getPackageInfo(this.getPackageName(), 0);
      String version = info.versionName;
      return version;
    } catch (Exception e) {
      e.printStackTrace();
      return "找不到版本号";
    }
  }
  1. 获取后台apk的版本号,大家自行实现;
  2. 用于版本更新的Service如下:
package com.ccclubs.pa.service;

import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;
import com.ccclubs.pa.R;
import com.ccclubs.pa.rxapp.App;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;


public class DownloadApkService extends IntentService {

  private static final String APP_NAME = "demo";

  public static final String APP_FILE_PATH = File.separator + APP_NAME + File.separator;

  // 文件存储
  private File saveDir;
  private File saveFile;
  private String mUrl;

  // 通知栏
  private NotificationManager updateNotificationManager = null;
  private Notification updateNotification = null;

  // 通知栏跳转Intent
  private Intent updateIntent = null;
  private PendingIntent updatePendingIntent = null;
  // 下载状态
  private final static int DOWNLOAD_COMPLETE = 0;
  private final static int DOWNLOAD_FAIL = 1;

  private RemoteViews contentView;
  private Handler mHandler = new Handler() {
    @Override public void handleMessage(Message msg) {
      super.handleMessage(msg);
      switch (msg.what) {
        case DOWNLOAD_COMPLETE:
          // 当下载完毕,自动安装APK
          installApk(App.getInstance(), saveFile);
          notifyNotification(100, 100);
          break;
        case DOWNLOAD_FAIL:
          notifyNotification(101,100);
          break;
        default:
          break;
      }
    }
  };

  public DownloadApkService() {
    super("com.demo.service.DownloadApkService");
  }

  @Override public int onStartCommand(Intent intent, int flags, int startId) {
    mUrl = intent.getStringExtra("url");
    createNotification();
    return super.onStartCommand(intent, flags, startId);
  }

  @Override protected void onHandleIntent(Intent intent) {
    Log.e("JP", "begin onHandleIntent() in " + this);
    Message message = mHandler.obtainMessage();
    message.what = DOWNLOAD_COMPLETE;
    if (saveDir != null && !saveDir.exists()) {
      saveDir.mkdirs();
    }
    if (saveFile != null && !saveFile.exists()) {
      try {
        saveFile.createNewFile();
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
    try {
      long downloadSize = downloadFile(mUrl, saveFile);
      if (downloadSize > 0) {// 下载成功
        mHandler.sendMessage(message);
      }
    } catch (Exception ex) {
      message.what = DOWNLOAD_FAIL;
      mHandler.sendMessage(message);// 下载失败
    }
  }

  private void createNotification() {
    String downloadDir = APP_FILE_PATH;
    apkUrl = mUrl;
    // 如果有SD卡,则创建APK文件
    if (android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment
        .getExternalStorageState())) {

      saveDir = new File(Environment.getExternalStorageDirectory(),
          downloadDir);
      saveFile = new File(saveDir.getPath(), "demo.apk");
    }
    this.updateNotificationManager = (NotificationManager) App.getInstance()
        .getSystemService(App.getInstance().NOTIFICATION_SERVICE);
    updateNotification = new Notification(
        R.mipmap.ic_launcher,//应用的图标
        "正在下载...",
        System.currentTimeMillis());
    updateNotification.flags = Notification.FLAG_AUTO_CANCEL;
    // 设置下载过程中,点击通知栏,回到主界面
    updateIntent = new Intent();
    updatePendingIntent = PendingIntent.getActivity(App.getInstance(), 0,
        updateIntent, 0);
    updateNotification.contentIntent = updatePendingIntent;
    /**自定义  Notification 的显示*/
    contentView = new RemoteViews(getPackageName(), R.layout.layout_notification_update);
    contentView.setProgressBar(R.id.progress, 100, 0, false);
    contentView.setTextViewText(R.id.tv_progress, "0%");
    updateNotification.contentView = contentView;
    updateNotificationManager.notify(R.layout.layout_notification_update, updateNotification);
  }

  private void notifyNotification(long percent, long length) {
    if(percent == length) {
      contentView.setTextViewText(R.id.tv_txt, "下载完成");
    } else if(percent > length) {
      contentView.setTextViewText(R.id.tv_txt, "下载失败,请检查网络连接");
    } else {
      contentView.setTextViewText(R.id.tv_txt, "正在下载...");
    }
    contentView.setTextViewText(R.id.tv_progress, (percent * 100 / length) + "%");
    contentView.setProgressBar(R.id.progress, (int) length, (int) percent, false);
    updateNotification.contentView = contentView;
    updateNotificationManager.notify(R.layout.layout_notification_update, updateNotification);
  }

  public long downloadFile(String downloadUrl, File saveFile) throws Exception {
    int downloadCount = 0;
    int currentSize = 0;
    long totalSize = 0;
    int updateTotalSize = 0;
    int rate = 0;// 下载完成比例

    HttpURLConnection httpConnection = null;
    InputStream is = null;
    FileOutputStream fos = null;

    try {
      URL url = new URL("http://" + downloadUrl);
      httpConnection = (HttpURLConnection) url.openConnection();
      httpConnection.setRequestProperty("User-Agent",
          "PacificHttpClient");
      if (currentSize > 0) {
        httpConnection.setRequestProperty("RANGE", "bytes="
            + currentSize + "-");
      }
      httpConnection.setConnectTimeout(200000);
      httpConnection.setReadTimeout(200000);
      updateTotalSize = httpConnection.getContentLength();// 获取文件大小
      if (httpConnection.getResponseCode() == 404) {
        throw new Exception("fail!");
      }
      is = httpConnection.getInputStream();
      fos = new FileOutputStream(saveFile, false);
      byte buffer[] = new byte[1024 * 1024 * 3];
      int readsize = 0;
      while ((readsize = is.read(buffer)) != -1) {
        fos.write(buffer, 0, readsize);

        totalSize += readsize;// 已经下载的字节数
        rate = (int) (totalSize * 100 / updateTotalSize);// 当前下载进度
        // 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次
        if ((downloadCount == 0) || rate - 0 > downloadCount) {
          downloadCount += 1;
          notifyNotification(totalSize, httpConnection.getContentLength());
        }
      }
    } finally {
      if (httpConnection != null) {
        httpConnection.disconnect();
      }
      if (is != null) {
        is.close();
      }
      if (fos != null) {
        fos.close();
      }
    }
    return totalSize;
  }

  public static void installApk(Context context, File file) {
    Intent intent = new Intent();
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.setAction(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(file),
        "application/vnd.android.package-archive");
    context.startActivity(intent);
  }
}

xml文件代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    android:padding="5dp"
    android:orientation="horizontal">

    <ImageView
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:background="@mipmap/ic_launcher"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="10dp"
        android:orientation="vertical">
        <RelativeLayout
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            >
            <TextView
                android:id="@+id/tv_txt"
                android:layout_centerVertical="true"
                android:padding="5dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="正在下载..."
                />
            <TextView
                android:id="@+id/tv_progress"
                android:layout_alignParentRight="true"
                android:padding="5dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="0%"
                />
        </RelativeLayout>

        <ProgressBar
            android:padding="5dp"
            android:id="@+id/progress"
            style="?android:attr/progressBarStyleHorizontal"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content" />
    </LinearLayout>

</LinearLayout>

记得把这个Service在AndroidManifest中进行注册。
首先这是一个IntentService,与普通的Service最大的区别就是,IntentService执行耗时的任务不需要新开一个线程,并且执行完任务后会自动销毁。其他的没什么好说的,都是一些非常简单的代码,相信大家都能读懂。
这里说一个小波折:就是我自己在用这个Service下载apk并进行安装的时候,都是没有问题的,但是同事用了我的Service居然老是出现apk解析失败的错误。我想要么就是apk没有下载完成,要么就是apk本身的错误。后来看了一下,原来后台给的链接是.html文件,所以我们下载的并不是apk文件,而是一个html网页,正常的链接应该是一个.apk文件,如果是html文件,我们应该调用浏览器打开这个链接来实现更新,或者用WebView把这个网页加载出来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值