昨天在做apk的版本更新时遇到一个问题是,安装后会提示已有不同签名的应用存在。然后我就蒙圈了,一一进行排查,后来才发现,是我手机上已有低版本的应用,而这个应用是直接用android studio 部署上去的,它会是用的默认签名,所以会报有不同签名的应用存在,所以我又重新打个包安装后,提示更新,下载后就成功了。
后来又遇到一种情况,就是apk下载不下来,然后我把从后台获取的apk下载的url放到pc端,同样下载不下来,和后台反应,原来是后台配置错了,给返回的url是错误的。。。。也是醉了。
更新代码如下:
public class UpdateService extends Service { // 标题 private int titleId = 0; // 文件存储 private File updateDir = null; private File updateFile = null; // 通知栏 private NotificationManager updateNotificationManager = null; private Notification.Builder 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; //获取更新apk的 url路径 // private String urlString; //更新apk的路径 是从后台获取的 private String apkUrl; @Override public IBinder onBind(Intent intent) { return null; } @SuppressWarnings("deprecation") @Override public int onStartCommand(Intent intent, int flags, int startId) { // 获取传值 if (intent!=null){ titleId = intent.getIntExtra("titleId", 0); apkUrl = intent.getStringExtra("apkUrl"); } System.out.println("titleId-----------" + titleId); // 创建文件 if (Environment.MEDIA_MOUNTED.equals(Environment .getExternalStorageState())) { updateDir = new File(Environment.getExternalStorageDirectory(), App.downloadDir); updateFile = new File(updateDir.getPath(), getResources() .getString(titleId) + ".apk"); } this.updateNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); this.updateNotification = new Notification.Builder(this); // 设置下载过程中,点击通知栏,回到主界面 updateIntent = new Intent(this, SettingAct.class); updatePendingIntent = PendingIntent.getActivity(this, 0, updateIntent, 0); // 设置通知栏显示内容 updateNotification.setSmallIcon(R.mipmap.logo).setContentTitle("").setContentText("开始下载"); updateNotification.setContentIntent(updatePendingIntent); // 发出通知 updateNotificationManager.notify(0, updateNotification.getNotification()); // 开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞 new Thread(new updateRunnable()).start();// 这个是下载的重点,是下载的过程 return super.onStartCommand(intent, flags, startId); } private Handler updateHandler = new Handler() { @SuppressWarnings("deprecation") @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOAD_COMPLETE: // 点击安装PendingIntent Uri uri = Uri.fromFile(updateFile); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); updatePendingIntent = PendingIntent.getActivity( UpdateService.this, 0, installIntent, 0); updateNotification.setDefaults(Notification.DEFAULT_SOUND);// 铃声提醒 // updateNotification.setLatestEventInfo(UpdateService.this, // "惠逛街", "下载完成,点击安装。", updatePendingIntent); updateNotification.setSmallIcon(R.mipmap.logo).setContentTitle("惠逛街").setContentText("下载完成,点击安装").setContentIntent(updatePendingIntent); updateNotificationManager.notify(0, updateNotification.getNotification()); // 停止服务 stopSelf(); break; case DOWNLOAD_FAIL: // 下载失败 // updateNotification.setLatestEventInfo(UpdateService.this, // "", "下载完成,点击安装。", updatePendingIntent); updateNotification.setSmallIcon(R.mipmap.logo).setContentTitle("").setContentText("下载完成,点击安装").setContentIntent(updatePendingIntent); updateNotificationManager.notify(0, updateNotification.getNotification()); break; default: stopSelf(); } } }; class updateRunnable implements Runnable { Message message = updateHandler.obtainMessage(); public void run() { message.what = DOWNLOAD_COMPLETE; //开启请求获取http://t.doolii.cn/m/pub/upgrade?versionCode=1 中的url 其中的参数只是versionCode // getUrl(); try { // 增加权限; if (!updateDir.exists()) { updateDir.mkdirs(); } if (!updateFile.exists()) { updateFile.createNewFile(); } // 下载函数,以QQ为例子 // 增加权限; //测试环境 //http://www.doolii.cn/static/doolii/apk/test-apk/doolii.apk //生产环境 // http://www.doolii.cn/static/doolii/apk/doolii.apk long downloadSize = downloadUpdateFile( apkUrl, updateFile); if (downloadSize > 0) { // 下载成功 updateHandler.sendMessage(message); } } catch (Exception ex) { ex.printStackTrace(); message.what = DOWNLOAD_FAIL; // 下载失败 updateHandler.sendMessage(message); } } } @SuppressWarnings("deprecation") public long downloadUpdateFile(String downloadUrl, File saveFile) throws Exception { // 这样的下载代码很多,我就不做过多的说明 int downloadCount = 0; int currentSize = 0; long totalSize = 0; int updateTotalSize = 0; HttpURLConnection httpConnection = null; InputStream is = null; FileOutputStream fos = null; try { URL url = new URL(downloadUrl); httpConnection = (HttpURLConnection) url.openConnection(); httpConnection .setRequestProperty("User-Agent", "PacificHttpClient"); if (currentSize > 0) { httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-"); } httpConnection.setConnectTimeout(10000); httpConnection.setReadTimeout(20000); updateTotalSize = httpConnection.getContentLength(); if (httpConnection.getResponseCode() == 404) { throw new Exception("fail!"); } is = httpConnection.getInputStream(); fos = new FileOutputStream(saveFile, false); byte buffer[] = new byte[1024]; int readsize = 0; while ((readsize = is.read(buffer)) > 0) { fos.write(buffer, 0, readsize); totalSize += readsize; // 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次 if ((downloadCount == 0) || (int) (totalSize * 100 / updateTotalSize) - 10 > downloadCount) { downloadCount += 10; // updateNotification.setLatestEventInfo(UpdateService.this, // "正在下载", (int) totalSize * 100 / updateTotalSize // + "%", updatePendingIntent);updateNotification.setSmallIcon(R.mipmap.logo).setContentTitle("下载进度").setContentText("正在下载中..."); // for (int i = 0; i < updateTotalSize-1; i++) { // updateNotification.setProgress(updateTotalSize, (int) totalSize / updateTotalSize, false); // i 代表当前进度值 updateNotification.setProgress(100, downloadCount, false); // i 代表当前进度值// } updateNotificationManager.notify(0, updateNotification.getNotification()); } } fos.flush(); Log.i("apk....", saveFile.length()+""); } finally { if (httpConnection != null) { httpConnection.disconnect(); } if (is != null) { is.close(); } if (fos != null) { fos.close(); } } return totalSize; }}而检查版本是否需要更新是在闪屏页进行检查的。代码如下:/* * 闪屏页:判断用户是否已经登录,如果已经登录,直接进入主页,否则,进入登录页面? */ public class SplashActivity extends BaseActivity { private Button login; private RelativeLayout rlBackground; //商场列表 private ArrayList<MarketEntity> marketList; private String name; private int targetId;//商场id private UpdateBean update; private String apkUrl;//apk下载地址 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash); // 检查版本 checkVersion(); } //闪屏页 判断是否第一次登陆 private void splash() { // 闪屏的核心代码 new Handler().postDelayed(new Runnable() { @Override public void run() { Intent intent = new Intent(); // 从启动动画ui跳转到主ui // 判断是否已经登录,若登录跳转到首页,否则跳转到登录页面 if (SharedPerferenceUtils.getBoolean(SplashActivity.this, "isLogin", false)) { initMarketData(); intent.setClass(SplashActivity.this, MainActivity.class); } else { intent.setClass(SplashActivity.this, LoginActivity.class); } startActivity(intent); overridePendingTransition(R.anim.base_slide_in, R.anim.base_slide_right_out); SplashActivity.this.finish(); // 结束启动动画界面 } }, 1000); // 启动动画持续3秒钟 } private void checkVersion() { Integer versionCode = getVersion(); // 判断网络状态 if (!NetUtils.checkConnected(this)) { CommonUtils.showToastMsg(this, "网络不可用"); return; } // String url = Constant.Upgrade + "?current=" + getVersionName(); String url = Constant.Upgrade + "?current=" + 2; VolleyRequest.jsonRequest(SplashActivity.this, Request.Method.GET, url, Constant.HGJ_TAG, null, new VolleyInterface(SplashActivity.this, VolleyInterface.mListener, VolleyInterface.mErrorListener) { @Override public void onMySuccess(JSONObject result) { System.out.println("版本升级result---" + result); if (result != null) { try { if (result.getInt("code") == 200) { update = GsonUtils.jsonToBean(result.getJSONObject("entity").toString(), UpdateBean.class); if (Integer.valueOf(update.getCode()) <= getVersion()) { // 无需升级, // NOUpdate(); splash(); } else {//请求下来的版本》本地版本 需要升级 apkUrl = update.getUrl(); if (!StringUtils.isEmptyString(apkUrl)){ if (update.isMust()) { //强制升级 mustUpdate(); } else { Update(); } } } } } catch (JSONException e) { e.printStackTrace(); } } } @Override public void onMyError(VolleyError error) { // CommonUtils.showToastMsg(SplashActivity.this, "请求失败check"); Log.i("请求走了吗","请求失败check"); } }); } protected void mustUpdate() { // TODO Auto-generated method stub CustomDialog.Builder customBuilder = new CustomDialog.Builder( SplashActivity.this); customBuilder .setTitle("版本信息") .setMessage("有新版本" + update.getCode() + "。") .setNegativeButton("去升级", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); splash(); //开启更新服务UpdateService //这里为了把update更好模块化,可以传一些updateService依赖的值 //如布局ID,资源ID,动态获取的标题,这里以app_name为例 Intent updateIntent = new Intent(SplashActivity.this, UpdateService.class); updateIntent.putExtra("titleId", R.string.app_name); updateIntent.putExtra("apkUrl",apkUrl); startService(updateIntent); } }); CustomDialog dialog = customBuilder.create(); dialog.show(); } /** * @param 设定文件 * @return void 返回类型 * @Description: TODO() */ protected void Update() { // TODO Auto-generated method stub CustomDialog.Builder customBuilder = new CustomDialog.Builder( SplashActivity.this); customBuilder .setTitle("版本信息") .setMessage("有新版本" + update.getCode() + "。") .setPositiveButton("知道了", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }) .setNegativeButton("去升级", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); splash(); //开启更新服务UpdateService //这里为了把update更好模块化,可以传一些updateService依赖的值 //如布局ID,资源ID,动态获取的标题,这里以app_name为例 Intent updateIntent = new Intent(SplashActivity.this, UpdateService.class); updateIntent.putExtra("titleId", R.string.app_name); updateIntent.putExtra("apkUrl",apkUrl); startService(updateIntent); } }); CustomDialog dialog = customBuilder.create(); dialog.show(); } /** * @param 设定文件 * @return void 返回类型 * @Description: TODO() */ protected void NOUpdate() { // TODO Auto-generated method stub CustomDialog.Builder customBuilder = new CustomDialog.Builder( SplashActivity.this); customBuilder .setTitle("版本信息") .setMessage("当前已是最新版本。") .setNegativeButton("知道了", new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }); CustomDialog dialog = customBuilder.create(); dialog.show(); } // 获取版本号 private int getVersion() { // 获取packagemanager的实例 PackageManager packageManager = getPackageManager(); // getPackageName()是你当前类的包名,0代表是获取版本信息 PackageInfo packInfo = null; try { packInfo = packageManager.getPackageInfo(getPackageName(), 0); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } Integer version = packInfo.versionCode; return version; } // 获取版本 private String getVersionName() { // 获取packagemanager的实例 PackageManager packageManager = getPackageManager(); // getPackageName()是你当前类的包名,0代表是获取版本信息 PackageInfo packInfo = null; try { packInfo = packageManager.getPackageInfo(getPackageName(), 0); } catch (PackageManager.NameNotFoundException e) { e.printStackTrace(); } String version = packInfo.versionName; return version; } //商场列表 private void initMarketData() { Map<Object, Object> params = new HashMap<>(); final JSONObject json = new JSONObject(params);//map转换成JSONObject VolleyRequest.jsonRequest(this, Request.Method.GET, Constant.MarketList, Constant.HGJ_TAG, json, new VolleyInterface(SplashActivity.this, VolleyInterface.mListener, VolleyInterface.mErrorListener) { @Override public void onMySuccess(JSONObject result) { if (result != null) { System.out.println("商场列表请求marketList------" + result); try { if (result.getInt("code") == 200) { JSONArray jsonArray = result.getJSONArray("entity"); marketList = new ArrayList<MarketEntity>(); if (jsonArray!=null&&jsonArray.length()!=0){ for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.optJSONObject(i); MarketEntity marketEntity = new MarketEntity(); marketEntity.setAddress(jsonObject.optString("address")); targetId = jsonObject.optInt("id"); marketEntity.setId(targetId); name = jsonObject.optString("name"); marketEntity.setName(name); marketEntity.setPhone(jsonObject.optString("phone")); marketList.add(marketEntity); App.markets = marketList; } System.out.println("商场列表list---" + marketList); } } else { CommonUtils.showToastMsg(SplashActivity.this, result.getString("msg")); } } catch (JSONException e) { e.printStackTrace(); } } } @Override public void onMyError(VolleyError error) { CommonUtils.showToastMsg(SplashActivity.this, "请求失败"); Log.i("----VolleyError----", error + ""); } }); } }