Android软件自动更新,通知栏显示,项目源码
2015-03-29 10:40
731 查看
此处json解析使用的是阿里的FastJson
package com.szy.update; /** * 全局控制 * @author LSC * */ public class Config { //测试网址 public static final String BASE_URL = "http://127.0.0.1"; //版本更新,从服务器获取apk信息 public static final String UPDATE_JSON_URL = BASE_URL + "/version/bh_apk_version.json"; //apk存放的文件夹, public static final String APK_STROAGE_DIR = "/sdcard/update"; //apk存放位置,在实际应用中apk的名字最好固定下来 public static final String APK_STROAGE_ADDRESS = APK_STROAGE_DIR + "/MFTicketTerminalCommonBlackHand-1.7.0.apk"; }
<span style="color:#ff0000;">此处是主要类,启动次此类时请求服务器</span>
package com.szy.update; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import android.app.Activity; import android.app.AlertDialog; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; /** * auto updateVersion * @author LSC * */ public class MainActivity extends Activity implements OnClickListener{ /* * 从服务器获取到的版本信息,json格式 * http://127.0.0.1/version/bh_apk_version.json * { "apk_version": "7", "apk_md5": "e55f52386e109abba75f4cc83d3629dd", "apk_url": "http://127.0.0.1/downloads/MFTicketTerminalCommonBlackHand-1.7.0.apk", "base_url": "http://127.0.0.1" }*/ private String apkDownloadUrl;//apk下载地址 private DownloadApkAndInstall mDownloadApkInstall; private Button updateServiceBtn; private int mCurrentVersionCode;//当前版本versionCode private int mServerVersionCode;//服务器版本versionCode private Handler mHandler = new Handler(){ public void handleMessage(Message msg) { compareVersionCoder(mCurrentVersionCode,msg.arg1); }; }; @Override public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); try { mCurrentVersionCode = getCurrentVersionCode(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Message msg = new Message(); mServerVersionCode = Integer.valueOf(getServerVersionCode( getJsonHttpURLConnection(Config.UPDATE_JSON_URL))); msg.arg1 = mServerVersionCode; mHandler.sendMessage(msg); } }).start(); initView(); } public void initView(){ updateServiceBtn = (Button) findViewById(R.id.btnUpdate); updateServiceBtn.setOnClickListener(this); } /* * 获取当前程序的版本号 VersionCode */ int getCurrentVersionCode() throws Exception{ PackageManager packageManager = getPackageManager(); PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0); return packInfo.versionCode; } /* * 获取当前程序的 versionName */ String getCurrentVersionName() throws Exception{ PackageManager packageManager = getPackageManager(); PackageInfo packInfo = packageManager.getPackageInfo(getPackageName(), 0); return packInfo.versionName; } /** * get apk name * @param context * @return */ public static String getAppName(Context context) { String verName = context.getResources() .getText(R.string.app_name).toString(); return verName; } /** * get server VersionCode and apkDownloadUrl * @return */ private String getServerVersionCode (String jsonByNet){ JSONObject response = JSON.parseObject(jsonByNet); String serverVersionCode = response.getString("apk_version"); apkDownloadUrl = response.getString("apk_url"); return serverVersionCode; } /** * compare serverVersionCode with currentVersionCode * * Whether or not to update */ public void compareVersionCoder(int currentVersionCode,final int serverVersionCode){ try { if(serverVersionCode > currentVersionCode){ new AlertDialog.Builder(this).setTitle("提示").setMessage("您的版本过低,我们建议您更新到最新的版本。") .setPositiveButton("sure", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { mDownloadApkInstall = new DownloadApkAndInstall(MainActivity.this); mDownloadApkInstall.updateVersion(mServerVersionCode, MainActivity.this, apkDownloadUrl); dialog.dismiss(); } }).setNegativeButton("next update", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } }).show(); }else{ Toast.makeText(this, "Is currently the latest version", Toast.LENGTH_LONG).show(); } } catch (NumberFormatException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } /** * get json String * @param jsonURL * @return */ public String getJsonHttpURLConnection(String jsonURL){ InputStream is = null; try { URL url = new URL(jsonURL); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setReadTimeout(5000); conn.setConnectTimeout(5000); if(conn.getResponseCode() == 200){ //获取数据 is = conn.getInputStream(); BufferedReader buffer = new BufferedReader(new InputStreamReader(is,"utf-8")); String inputLine = null; StringBuffer sbContent = new StringBuffer(); while ((inputLine = buffer.readLine()) != null){ sbContent.append(inputLine); } System.out.println(sbContent.toString()); return sbContent.toString(); }else{ Toast.makeText(this, "连接服务器失败", Toast.LENGTH_LONG).show(); } } catch (MalformedURLException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } @Override public void onClick(View v) { // TODO Auto-generated method stub NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Notification notification = new Notification(R.drawable.notify_icon, "poap", System.currentTimeMillis()); Intent intent = new Intent(this,NotificationActivity.class); PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); notification.setLatestEventInfo(this, "This is content title", "This is content text", pi); manager.notify(1, notification); Log.d("MainActivity","Thread id is "+Thread.currentThread().getId()); } }
此处是service,大家不要忘记注册service和activity,Android的四大组件在清单文件Manifest.xml都需要注册的,也不要忘了设置两个权限
package com.szy.update; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.Intent; import android.net.Uri; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Log; import android.widget.RemoteViews; import android.widget.Toast; public class UpdateService extends Service { private static final String TAG = "UpdateService"; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } private String titleId; private File updateFile = null;//文件存储 //通知栏 private NotificationManager updateNotificationManager = null; private Notification updateNotification = null; //通知栏跳转Intent private Intent updateIntent = null; private PendingIntent updatePendingIntent = null; private String updateurl; RemoteViews contentView; @Override public int onStartCommand(Intent intent, int flags, int startId) { titleId = intent.getStringExtra("titleId"); updateurl=intent.getStringExtra("updateurl"); updateFile = new File(Config.APK_STROAGE_ADDRESS); updateNotificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); updateNotification = new Notification(R.drawable.notify_icon, titleId+"开始下载", System.currentTimeMillis()); updateIntent = new Intent(UpdateService.this,Notification.class); updatePendingIntent = PendingIntent.getActivity(this,0,updateIntent,PendingIntent.FLAG_CANCEL_CURRENT); // updateNotification.setLatestEventInfo(this,"***","0%",updatePendingIntent); contentView =new RemoteViews(this.getPackageName(),R.layout.notificationupdate); contentView.setTextViewText(R.id.tvnow, "正在下载..."); contentView.setTextViewText(R.id.tvjingdu, "0%"); contentView.setProgressBar(R.id.progress_horizontal, 100, 0, false); updateNotification.contentView=contentView; //发出通知 updateNotificationManager.notify(1,updateNotification); //开启一个新的线程下载,如果使用Service同步下载,会导致ANR问题,Service本身也会阻塞 new Thread(new updateRunnable()).start();//这个是下载的重点,是下载的过程 return super.onStartCommand(intent, flags, startId); } private Handler updateHandler = new Handler(){ @Override public void handleMessage(Message msg) { switch (msg.what) { case DOWNLOAD_COMPLETE: //点击安装PendingIntent Boolean iswanzheng=Utils.getUninatllApkInfo(UpdateService.this, updateFile.toString()); if(iswanzheng){ 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.defaults = Notification.DEFAULT_SOUND;//铃声提醒 updateNotification.setLatestEventInfo(UpdateService.this, "***", "下载完成,点击安装。", updatePendingIntent); updateNotificationManager.notify(1, updateNotification); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getApplicationContext().startActivity(installIntent); }else{ Toast.makeText(UpdateService.this, "下载包不完整,请重新下载...", Toast.LENGTH_SHORT).show(); } //停止服务 stopSelf(); break; case DOWNLOAD_FAIL: //下载失败 updateNotification.setLatestEventInfo(UpdateService.this, "***", "下载失败,可能是网络 不好。", updatePendingIntent); updateNotificationManager.notify(1, updateNotification); stopSelf(); break; default: stopSelf(); } } }; public class updateRunnable implements Runnable{ Message message = updateHandler.obtainMessage(); public void run() { message.what = DOWNLOAD_COMPLETE; try{ if(!updateFile.exists()){ updateFile.createNewFile(); } //增加权限; long downloadSize = downloadUpdateFile(updateurl,updateFile); if(downloadSize>0){ //下载成功 updateHandler.sendMessage(message); } }catch(Exception ex){ ex.printStackTrace(); message.what = DOWNLOAD_FAIL; //下载失败 updateHandler.sendMessage(message); } } } 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[4096]; int readsize = 0; while((readsize = is.read(buffer)) > 0){ fos.write(buffer, 0, readsize); totalSize += readsize; //为了防止频繁的通知导致应用吃紧,百分比增加4才通知一次 if((downloadCount == 0)||(int) (totalSize*100/updateTotalSize)-4>downloadCount){ downloadCount += 4; //updateNotification.setLatestEventInfo(UpdateService.this, "正在下载...", (int)totalSize*100/updateTotalSize+"%", updatePendingIntent); contentView.setProgressBar(R.id.progress_horizontal, 100, downloadCount, false); contentView.setTextViewText(R.id.tvjingdu, (int)totalSize*100/updateTotalSize+"%"); updateNotificationManager.notify(1, updateNotification); } } }catch(Exception ex){ ex.printStackTrace(); Log.e(TAG, ex.toString()); } finally { if(httpConnection != null) { httpConnection.disconnect(); } if(is != null) { is.close(); } if(fos != null) { fos.close(); } } return totalSize; } //下载状态 private final static int DOWNLOAD_COMPLETE = 0; private final static int DOWNLOAD_FAIL = 1; }
当在通知栏点击时,会跳转到此类
package com.szy.update; import android.app.Activity; import android.os.Bundle; public class NotificationActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.notification_download); } }
此类为工具类
package com.szy.update; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.SharedPreferences; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Environment; import android.util.Log; import android.widget.Toast; public class Utils { private static final String TAG = "Utils"; public static String digits = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLIMNOPQRSTUVWXYZ~!@#$%^&*()_+{}:\'|<>?-=[];\"\\,./"; private static List<Activity> activityList = new ArrayList<Activity>(); // 添加Activity到容器中 public static void addActivity(Activity activity) { if (activityList != null && activity != null) { activityList.add(activity); } } // 遍历所有Activity并finish public static void exit() { for (Activity activity : activityList) { if (activity != null) { activity.finish(); } } activityList.clear(); } /** * SDCard 根目录 * * @return */ public static String getSDCardRootPath() { File sdCardDir = null; boolean sdcardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED); if (sdcardExist) { sdCardDir = Environment.getExternalStorageDirectory(); StringBuffer buffer = new StringBuffer(); buffer.append(sdCardDir); buffer.append(File.separator); buffer.append("guideBuyTicket"); return buffer.toString(); } return null; } public static SharedPreferences getSP() { // SharedPreferences sp = CrashApplication.app.getSharedPreferences(Config.CONFIG_FILE_NAME, Context.MODE_PRIVATE); // return sp; return null; } public static void updateVersion(String apkMd5, String versionName, Context context, String url) { if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { File updateDir = new File(Environment.getExternalStorageDirectory(), ""); File updateFile = new File(updateDir.getPath(), versionName + ".apk"); if (updateFile.exists()) { if (Utils.getUninatllApkInfo(context, updateFile.getAbsolutePath())) { Uri uri = Uri.fromFile(updateFile); Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setDataAndType(uri, "application/vnd.android.package-archive"); context.startActivity(installIntent); } else { Intent updateIntent = new Intent(context, UpdateService.class); updateIntent.putExtra("titleId", R.string.app_name); updateIntent.putExtra("updateurl", url); updateIntent.putExtra("newversion", versionName); context.startService(updateIntent); Toast.makeText(context, "下载包不完整,正在下载...!", Toast.LENGTH_SHORT).show(); } } else { Intent updateIntent = new Intent(context, UpdateService.class); updateIntent.putExtra("titleId", R.string.app_name); updateIntent.putExtra("updateurl", url); updateIntent.putExtra("newversion", versionName); context.startService(updateIntent); } } else { Toast.makeText(context, "你没有sd卡,请安装", Toast.LENGTH_SHORT).show(); } } /** * 判断未安装apk包的完整性 * * @param context * @param filePath * @return */ public static boolean getUninatllApkInfo(Context context, String filePath) { boolean result = false; try { PackageManager pm = context.getPackageManager(); Log.e("archiveFilePath", filePath); PackageInfo info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES); String packageName = null; if (info != null) { result = true; } } catch (Exception e) { result = false; e.printStackTrace(); } return result; } public static String MD5(String inStr) { MessageDigest md5 = null; try { md5 = MessageDigest.getInstance("MD5"); } catch (Exception e) { System.out.println(e.toString()); e.printStackTrace(); return ""; } char[] charArray = inStr.toCharArray(); byte[] byteArray = new byte[charArray.length]; for (int i = 0; i < charArray.length; i++) byteArray[i] = (byte) charArray[i]; byte[] md5Bytes = md5.digest(byteArray); StringBuffer hexValue = new StringBuffer(); for (int i = 0; i < md5Bytes.length; i++) { int val = ((int) md5Bytes[i]) & 0xff; if (val < 16) hexValue.append("0"); hexValue.append(Integer.toHexString(val)); } return hexValue.toString(); } /** * 用md5判断apk是否完整 * * @param apkMd5 * @param path * @return */ // public static boolean isCompleByMd5(String apkMd5, String path) { // String apkStr = readString(path); // String curApkMd5 = MD5(apkStr); // LogUtil.i(TAG, "curApkMd5====" + curApkMd5); // if (apkMd5.equals(curApkMd5)) { // return true; // } // return false; // } /** * 以字节为单位读取文件,常用于读二进制文件,如图片、声音、影像等文件。 当然也是可以读字符串的。 */ /* 貌似是说网络环境中比较复杂,每次传过来的字符是定长的,用这种方式? */ public static String readString(String path) { try { // FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。 FileInputStream inStream = new FileInputStream(path); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length = -1; while ((length = inStream.read(buffer)) != -1) { bos.write(buffer, 0, length); // .write方法 SDK 的解释是 Writes count bytes from the byte array // buffer starting at offset index to this stream. // 当流关闭以后内容依然存在 } bos.close(); inStream.close(); return bos.toString(); // 为什么不一次性把buffer得大小取出来呢?为什么还要写入到bos中呢? return new(buffer,"UTF-8") // 不更好么? // return new String(bos.toByteArray(),"UTF-8"); } catch (Exception e) { } return null; } /** * 验证手机号码 * * @param mobiles * @return */ public static boolean isMobileNO(String mobiles) { boolean flag = false; try { Pattern p = Pattern.compile("^1[34578][0-9]{9}$"); Matcher m = p.matcher(mobiles); flag = m.matches(); } catch (Exception e) { flag = false; } return flag; } /** * 验证身份证号码 * * @param mobiles * @return */ public static boolean isIdCard(String mobiles) { boolean flag = false; try { Pattern p = Pattern.compile("^(\\d{14}|\\d{17})(\\d|[xX])$"); Matcher m = p.matcher(mobiles); flag = m.matches(); } catch (Exception e) { flag = false; } return flag; } }
package com.szy.update; import java.io.File; import android.content.Context; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.net.Uri; import android.os.Environment; import android.util.Log; import android.widget.Toast; public class DownloadApkAndInstall { private Context mContext; private PackageManager pm; public DownloadApkAndInstall(Context context){ this.mContext = context; pm = context.getPackageManager(); } //打开APK程序代码 private void openFile(File file) { // TODO Auto-generated method stub Log.e("OpenFile", file.getName()); Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setAction(android.content.Intent.ACTION_VIEW); intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive"); mContext.startActivity(intent); } /** * get exist apk versionCode * @param apkPath * @return */ private int getApkVersionCode(String apkPath) { PackageInfo pi = pm.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES); int versionCode = 1; if (pi != null) { versionCode = pi.versionCode; } return versionCode; } /** * 判断未安装apk包的完整性 * * @param context * @param filePath * @return */ public boolean getUninatllApkInfo(Context context, String filePath) { boolean result = false; try { PackageManager pm = context.getPackageManager(); Log.e("archiveFilePath", filePath); PackageInfo info = pm.getPackageArchiveInfo(filePath, PackageManager.GET_ACTIVITIES); @SuppressWarnings("unused") String packageName = null; if (info != null) { result = true; } } catch (Exception e) { result = false; e.printStackTrace(); } return result; } public void updateVersion(int serverVersionCode, Context context, String url) { if (Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) { File updateDir = new File(Config.APK_STROAGE_DIR); if(!updateDir.exists()){ updateDir.mkdirs(); } File updateFile = new File(Config.APK_STROAGE_ADDRESS); if (updateFile.exists()) { if(getUninatllApkInfo(mContext, updateFile.toString())){ if (serverVersionCode > getApkVersionCode(updateFile.toString())) { updateFile.delete(); Intent updateIntent = new Intent(context, UpdateService.class); updateIntent.putExtra("titleId", "***"); updateIntent.putExtra("updateurl", url); updateIntent.putExtra("updateFile",updateFile.toString()); // updateIntent.putExtra("newversion", versionName); context.startService(updateIntent); } else { System.out.println("此版本已存在"); openFile(updateFile); return; } }else{ System.out.println("文件损坏"); updateFile.delete(); Intent updateIntent = new Intent(context, UpdateService.class); updateIntent.putExtra("titleId", "***"); updateIntent.putExtra("updateurl", url); updateIntent.putExtra("updateFile",updateFile.toString()); // updateIntent.putExtra("newversion", versionName); context.startService(updateIntent); } } else { Intent updateIntent = new Intent(context, UpdateService.class); updateIntent.putExtra("titleId", "***"); updateIntent.putExtra("updateurl", url); updateIntent.putExtra("updateFile",updateFile.toString()); // updateIntent.putExtra("newversion", versionName); context.startService(updateIntent); } } else { Toast.makeText(context, "你没有sd卡,请安装", Toast.LENGTH_SHORT).show(); } } }
相关文章推荐
- android之apk自动更新采用Notification通知提示并显示下载进度
- android之apk自动更新采用Notification通知提示并显示下载进度
- 安卓自动更新,静默更新,替换友盟更新可以在通知栏里显示更新下载进度,几行代码快速实现Android下载更新
- Android 通过蒲公英pgyer的接口 Service 实现带进度下载App 通知栏显示 在线更新 自动更新Demo
- Android 自动更新 后代通知栏显示进度
- android开发进行自动更新时怎么下载软件到手机内存,显示实现下载到SD卡了
- Android 通过蒲公英pgyer的接口 Service 实现带进度下载App 通知栏显示 在线更新 自动更新Demo
- 【原】Android热更新开源项目Tinker源码解析系列之一:Dex热更新
- 使用清华大学开源软件镜像AOSP的“每月更新初始化包”更新指定版本的Android源码
- 更新模块通知栏显看不到当前进度,以及更新下载中可以清理通知问题,华为强制更新退出软件后台下载不显示通知问题
- Android中的软件的自动更新(包括静默更新,需Root权限)
- Android 简单实现app通知栏更新及显示进度
- Android软件更新包的自动更新
- android开发视频监控时,抓拍图片存储在相册,图片无法显示问题?通知相册更新即可
- 更新模块通知栏显看不到当前进度,以及更新下载中可以清理通知问题,华为强制更新退出软件后台下载不显示通知问题
- android实现软件自动更新的步骤
- Android App自动更新之通知栏下载
- Android简易的自动更新(通知栏+系统下载),包含7.0系统解析安装包失败的处理
- Android 超简单音乐播放器(八)通知栏切换显示更新歌曲 服务和活动之间的相互通信~
- Android下载更新(兼容7.0文件,支持5.0通知栏显示Icon)