更新android应用到最新版本
更新应用的最新版本是每个上线apk都必须有的功能。
那么这个功能要怎样实现呢?
一、首先我们理一下具体的思路:
1、最好采用异步请求的方式与服务器交互。即创建一个类,继承AsyncTask类。
2、判断当前的(即客户端)apk版本是否小于服务器端的apk版本,如果小于,则向服务器端发送请求下载最新版本的apk。
3、下载最新的apk后,必须在客户端创建一个路径用来存放下载好的apk文件。所以在这一步之前,需在客户端创建一个路径。
4、下载apk得花费一点时间,为了更好的用户体验,我们最好写一个进度框或一个动画显示正在下载的进度或者提示用户apk正在更新。
5、通过更新apk接口,取得服务器返回的json或xml数据,包括最新的版本信息、下载apk的url、MD5、文件大小。解析json或xml数据,并将数据保存到一个bean文件中。
6、通过HttpClient取得服务器返回的安装包数据,保存到输入流中。
7、将安装包数据保存为一个.tmp文件。如:安装包名为news,则保存的文件名为news.tmp。
8、当安装包数据全部读取完成后,再将.tmp文件改名为以安装包名相同的文件,即news。
9、将文件news进行解压,即可得到.apk文件。
二、具体实现代码:
SettingActivity.java :
1 public class SettingActivity extends Activity { 2 private UpdateApkTask updateApkTask;// 更新apk线程 3 private ProgressDialog progressDialog;// 删除文件及数据库的load界面 4 5 @Override 6 protected void onCreate(Bundle savedInstanceState) { 7 super.onCreate(savedInstanceState); 8 9 setContentView(R.layout.activity_setting); 10 11 initUI(); 12 restorationDialog(); 13 14 } 15 16 protected void initUI() { 17 updateApk(); 18 } 19 20 /** 21 * 初始化progressDialog 22 */ 23 private void restorationDialog() { 24 25 progressDialog = new ProgressDialog(this); 26 progressDialog.setMessage(getString(R.string.restore_pDialog_title)); 27 progressDialog.setTitle(getString(R.string.hint)); 28 progressDialog.setCancelable(false);// 不可撤销 29 30 } 31 32 private updateApk(){ 33 stopUpdateApkTask(); 34 updateApkTask = new UpdateApkTask(); 35 FileUtils2.createFile(MyMount 36 .getImageStorageDir(SettingActivity.this)); 37 38 updateApkTask.execute(new String[] { MyMount 39 .getImageStorageDir(SettingActivity.this) }); 40 } 41 42 /** 43 * 更新程序版本线程 44 * 45 */ 46 private class UpdateApkTask extends AsyncTask<String, Integer, Boolean> { 47 48 private boolean tag = false; 49 public UpdateApkTask() { 50 progressDialog.show(); 51 progressDialog.setMessage(getString(R.string.apk_pDialog_title)); 52 } 53 54 // onPreExecute方法用于在执行后台任务前做一些UI操作 55 @Override 56 protected void onPreExecute() { 57 58 super.onPreExecute(); 59 60 } 61 62 // doInBackground方法内部执行后台任务,不可在此方法内修改UI 63 @Override 64 protected Boolean doInBackground(String... params) { 65 CodeUpdate mCodeUpdate = NetworkDataUpdate.getInstance( 66 SettingActivity.this).GetCodeUpdate(); 67 if (mCodeUpdate != null && mCodeUpdate.getUpdatePackName() != null) { 68 69 // 如果用户当前的apk版本号小于服务器中的apk版本号,则下载最新版本的apk 70 if (Float.parseFloat(VersionUtil.getVersionCode(SettingActivity.this)) < Float 71 .parseFloat(mCodeUpdate.getVersion())) { 72 tag = true; 73 String downloadPath = mCodeUpdate.getUpdatePackName();// 获取URL //如果url加了密,比如是这种形式:"http://<Dns>:<Port>/api/json/reply/",则要进行解密操作 74 downloadPath = downloadPath.replace("<Dns>",KeltiIntenface.ipStr).replace("<Port>",KeltiIntenface.postStr);// 替换URL的ip及post 75 76 InputStream is = null; 77 FileOutputStream fos = null; 78 File tmpFile = null; 79 80 try { 81 HttpClient httpClient = new DefaultHttpClient(); 82 HttpGet httpGet = new HttpGet(downloadPath); 83 HttpResponse httpResponse = httpClient.execute(httpGet); 84 HttpEntity entity = httpResponse.getEntity(); 85 is = entity.getContent(); 86 87 if (httpResponse.getStatusLine().getStatusCode() != 200) { 88 89 return false; 90 } 91 // 新建文件,下载文件 92 tmpFile = new File(params[0] 93 + downloadPath.substring(downloadPath 94 .lastIndexOf("/") + 1) + ".tmp"); 95 96 if (is != null) { 97 fos = new FileOutputStream(tmpFile); 98 byte[] buf = new byte[1024 * 1024 * 4]; 99 int ch = -1; 100 while ((ch = is.read(buf)) != -1) { 101 fos.write(buf, 0, ch); 102 } 103 } 104 105 fos.flush(); 106 if (fos != null) { 107 fos.close(); 108 } 109 if (is != null) { 110 tmpFile.renameTo(new File(params[0] 111 + downloadPath.substring(downloadPath 112 .lastIndexOf("/") + 1))); 113 114 File mFile = new File(params[0] 115 + downloadPath.substring(downloadPath 116 .lastIndexOf("/") + 1)); 117 //解压下载完成后的文件,将mFile文件解压到params[0]目录,且解压完成后,将压缩包删除,以节省客户端的存储空间 118 if (DecompressionZip.upZipFile(mFile, params[0]) == 0) { 119 120 YLogUtil.printSpidLog("mFile="+mFile.toString()); 121 mFile.delete(); 122 return true; 123 } 124 125 } 126 } catch (ConnectException connectException) { 127 128 if (tmpFile != null && tmpFile.exists()) { 129 YLogUtil.printSpidLog("tmpFile="+tmpFile.toString()); 130 tmpFile.delete(); 131 } 132 connectException.printStackTrace(); 133 134 } catch (SocketTimeoutException socketTimeoutException) { 135 136 if (tmpFile != null && tmpFile.exists()) { 137 YLogUtil.printSpidLog("tmpFile="+tmpFile.toString()); 138 tmpFile.delete(); 139 } 140 socketTimeoutException.printStackTrace(); 141 142 } catch (Exception e) { 143 e.printStackTrace(); 144 145 } 146 } 147 148 } 149 return false; 150 } 151 152 // onProgressUpdate方法用于更新进度信息 153 @Override 154 protected void onProgressUpdate(Integer... values) { 155 156 super.onProgressUpdate(values); 157 } 158 159 // onPostExecute方法用于在执行完后台任务后更新UI,显示结果 160 @Override 161 protected void onPostExecute(Boolean result) { 162 163 super.onPostExecute(result); 164 165 progressDialog.dismiss(); 166 if (result) { 167 168 ToastUtils.showToast(SettingActivity.this, 169 getString(R.string.toast_download_succeed), false); 170 FileUtils2.openFile( 171 SettingActivity.this, 172 new File(MyMount 173 .getImageStorageDir(SettingActivity.this) 174 + YContants.apkPath)); 175 } else { 176 // 如果用户当前的apk版本号等于服务器中的apk版本号,则告诉用户已经是最新版本 177 if (!tag) { 178 ToastUtils.showToast(SettingActivity.this, getString(R.string.latestVersion), true); 179 180 }else { 181 ToastUtils.showToast(SettingActivity.this, 182 getString(R.string.toast_download_fail), false); 183 } 184 } 185 186 } 187 188 // onCancelled方法用于在取消执行中的任务时更改UI 189 @Override 190 protected void onCancelled() { 191 192 super.onCancelled(); 193 progressDialog.dismiss(); 194 } 195 196 } 197 198 private void stopUpdateApkTask() { 199 if (updateApkTask != null && !updateApkTask.isCancelled()) { 200 updateApkTask.cancel(true); 201 } 202 } 203 204 @Override 205 protected void onDestroy() { 206 207 stopUpdateApkTask(); 208 super.onDestroy(); 209 } 210 211 }
FileUtils2.java:
public class FileUtils2 {/*** 创建文件夹* * @param pathString* 文件夹路径*/public static boolean createFile(String pathString) {if (pathString == null || pathString.equals("")|| pathString.equals("null") || !pathString.contains("/")) {return false;} else {File file = new File(pathString.substring(0,pathString.lastIndexOf("/") + 1));if (!file.exists()) {try {// 按照指定的路径创建文件夹 file.mkdirs();} catch (Exception e) {e.printStackTrace();return false;}}return fileCanReadWrite(file);}}/*** 判断文件夹/文件是否可读写* * @param file* 文件路径* @return*/public static boolean fileCanReadWrite(File file) {if (file.canWrite() && file.canRead()) {return true;} else {return false;}}
/*** 安装程序* * @param context 上下文* @param file apk的保存路径*/public static void openFile(Context context, File file) {try {Intent mIntent = new Intent();mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);mIntent.setAction(android.content.Intent.ACTION_VIEW);mIntent.setDataAndType(Uri.fromFile(file),"application/vnd.android.package-archive");context.startActivity(mIntent);} catch (Exception e) {e.printStackTrace();ToastUtils.showToast(context,context.getResources().getString(R.string.toast_openApk_error), false);}}
}
ToastUtils.java:
public class ToastUtils {public static void showToast(Context context, String msg, Boolean isTimeLong){ int time = Toast.LENGTH_SHORT; if(isTimeLong){ time = Toast.LENGTH_LONG; } Toast toast = Toast.makeText(context, null, time); LinearLayout layout = (LinearLayout)toast.getView(); layout.setBackgroundResource(R.drawable.toast_bg);layout.setOrientation(LinearLayout.VISIBLE); layout.setGravity(Gravity.CENTER); TextView tv = new TextView(context); tv.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); tv.setGravity(Gravity.CENTER); tv.setTextColor(Color.parseColor("#000000")); tv.setTextSize(TypedValue.COMPLEX_UNIT_SP, 30); tv.setPadding(0, 0, 0, 0); tv.setText(msg); layout.addView(tv); toast.show(); } }
MyMount.java:
public class MyMount { /*** 获取图片,视频,html存储路径* * @return*/@SuppressLint("DefaultLocale")public static String getImageStorageDir(Context context) {String pathStr = "";File storageDirFile = new File("/mnt/");if (storageDirFile.isDirectory()) {String[] dirList = storageDirFile.list();if (dirList != null) {for (int i = 0; i < dirList.length; i++) {String dirString = (dirList[i]).toLowerCase();if (dirString.equals("sdcard")) {if (ifValid("/mnt/" + dirList[i] + "/")) {pathStr = dirList[i];}}}}}if (pathStr.equals("")) {return getFileDir(context) + "/spid/";}File mFile=new File("/mnt/" + pathStr + "/spid/");if (!mFile.exists()) {mFile.mkdirs();}return "/mnt/" + pathStr + "/spid/";} }
CodeUpdate.java:
public class CodeUpdate {private String ModuleId;private String Version;private String UpdatePackName;private String MD5;private String FileSize;public String getModuleId() {return ModuleId;}public void setModuleId(String moduleId) {ModuleId = moduleId;}public String getVersion() {return Version;}public void setVersion(String version) {Version = version;}public String getUpdatePackName() {return UpdatePackName;}public void setUpdatePackName(String updatePackName) {UpdatePackName = updatePackName;}public String getMD5() {return MD5;}public void setMD5(String mD5) {MD5 = mD5;}public String getFileSize() {return FileSize;}public void setFileSize(String fileSize) {FileSize = fileSize;}}
NetworkDataUpdate.java:
/*** 获取网络Json数据并解析,插入本地数据库**/ public class NetworkDataUpdate{private static NetworkDataUpdate instance;private Context context;//接口参数private String []propertyName={"datetime","clientID"};private ImageLoader imageLoader;private Des mDes=new Des();public NetworkDataUpdate(Context context){this.context=context; imageLoader=ImageLoader.getInstance(context, MyMount.getImageStorageDir(context));}public static NetworkDataUpdate getInstance(Context context){if (instance==null) {instance=new NetworkDataUpdate(context);}return instance;}/*** 更新apk接口* @return*/public CodeUpdate GetCodeUpdate(){String mac="";try {mac=mDes.createEncrypt(UniqueIdentifier.getInstance(context).getMac());} catch (UnsupportedEncodingException e1) {e1.printStackTrace();}String []propertyValue=new String[]{mac};String []propertyName=new String[]{"clientID"};//通过GetCodeUpdate接口,发送请求,从服务器端接收返回的json数据JSONObject jsonObject=UrlData2Json.getJSONObject(YContants.namespace, KeltiIntenface.FunctionName.GetCodeUpdate, KeltiIntenface.url, propertyName, propertyValue, null);if (jsonObject==null) {//返回数据为nullif(YContants.DEBUG) YLogUtil.printLog("codeUpdateJsonArray为空");return null;}if(YContants.DEBUG) YLogUtil.printLog(jsonObject);CodeUpdate codeUpdate=null;try {if (jsonObject.getInt("State")!=1) {//程序验证不通过,则返回nullreturn null;}JSONObject childJsonObject=jsonObject.getJSONObject("Data");codeUpdate=new CodeUpdate();codeUpdate.setModuleId(childJsonObject.getString("ModuleId"));codeUpdate.setVersion(childJsonObject.getString("Version"));codeUpdate.setUpdatePackName(childJsonObject.getString("UpdatePackName"));codeUpdate.setMD5(childJsonObject.getString("MD5"));codeUpdate.setFileSize(childJsonObject.getString("FileSize"));} catch (JSONException e) {e.printStackTrace();}if (codeUpdate.getModuleId()!=null&&!codeUpdate.getModuleId().equals("")) {DataAddDB.addApk(context,"1", codeUpdate);}return codeUpdate;} }
DataAddDB.java:
public class DataAddDB { /*** 向Apk表插入数据* @param context* @param downloadList*/public static void addApk(Context context,String appID,CodeUpdate codeUpdate){HashMap<String, Object> mHashMap=DButil2.getInstance(context).queryTableApk(appID);boolean isExist=false;//用于标记表id是否重复if (appID.equals(mHashMap.get(DBContants.TableApkUpdate.ID)+"")) {isExist=true;}ContentValues values=new ContentValues();values.put(DBContants.TableApkUpdate.ID, appID+"");values.put(DBContants.TableApkUpdate.VERSION, codeUpdate.getVersion());values.put(DBContants.TableApkUpdate.UpdatePackName, codeUpdate.getUpdatePackName());values.put(DBContants.TableApkUpdate.MD5, codeUpdate.getMD5());values.put(DBContants.TableApkUpdate.FileSize, codeUpdate.getFileSize());if (!isExist) {DButil2.getInstance(context).addTableApkUpdate(values);}else {DButil2.getInstance(context).updateTableApk(values, appID+"");}} }
DButils2.java:
public class DButil2 extends DBUtil1{//volatile关键字就是提示VM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。用于多线程访问,看作程度较轻的 synchronizedprivate volatile static DButil2 instance;private DButil2(Context context){super(context);}public static DButil2 getInstance(Context context){ifReadCount=0;if(instance==null){synchronized(DButil2.class){if(instance==null){instance=new DButil2(context);}}}return instance;} //*****************************************************apk更新************************************************public HashMap<String, Object>queryTableApk(String appID){Cursor cursor = db.rawQuery("select * from apkUpdate where Id=?",new String[]{appID+""});return queryTableApk(cursor);} }
DButil1.java:
public class DBUtil1 extends RootDBUtil {private volatile static DBUtil1 instance;protected DBUtil1(Context context) {super(context);}public static DBUtil1 getInstance(Context context){if(instance==null){synchronized(DBUtil1.class){if(instance==null){instance=new DBUtil1(context);}}}return instance;}/*** 查询apk表* @param cursor* @return*/public HashMap<String, Object>queryTableApk(Cursor cursor){HashMap<String, Object>mHashMap=new HashMap<String, Object>();try {while (cursor.moveToNext()) {mHashMap.put(DBContants.TableApkUpdate.ID, cursor.getString(0));mHashMap.put(DBContants.TableApkUpdate.VERSION, cursor.getString(1));mHashMap.put(DBContants.TableApkUpdate.UpdatePackName, cursor.getString(2));mHashMap.put(DBContants.TableApkUpdate.MD5, cursor.getString(3));mHashMap.put(DBContants.TableApkUpdate.FileSize, cursor.getString(4));}} catch (Exception e) {e.printStackTrace();}finally{if (!cursor.isClosed()) {cursor.close();}}return mHashMap;}}
RootDBUtil.java:
public class RootDBUtil {private volatile static RootDBUtil instance;SQLiteDatabase db;protected RootDBUtil(Context context) {db = new DBHelper(context).getWritableDatabase();}public static RootDBUtil getInstance(Context context) {if(instance==null){synchronized(RootDBUtil.class){if(instance==null){instance=new RootDBUtil(context);}}}return instance;}//******************************************************apk更新*******************************************************public synchronized void addTableApkUpdate(ContentValues values){try {db.insert(DBContants.TableApkUpdate.TABLE_NAME, null, values);} catch (Exception e) {e.printStackTrace();}}public synchronized void updateTableApk(ContentValues values,String id){try {db.update(DBContants.TableApkUpdate.TABLE_NAME, values, DBContants.TableApkUpdate.ID + " = ? ", new String[] { id });} catch (Exception e) {e.printStackTrace();}} }
DBHelper.java:
public class DBHelper extends SQLiteOpenHelper {/*** 数据库版本*/private static final int VERSION = 1;/*** 数据库名称*/public static final String NAME = "spidclient.db";private Context context;/*** * @param name* 数据库文件名* @param factory* 游标工厂* @param version* 数据库版本,最小值为1*/public DBHelper(Context context) {super(context, NAME, null, VERSION);this.context=context;}/*** 第一次创建数据库的时候调用*/public void onCreate(SQLiteDatabase db) {/*** * create table t_contact(id integer primary key autoincrement, name* text, photo integer, phone text, address text, email text, pin_yin* text);* */createUpdateApk(db);}/*** 当数据库版本改变的时候调用*/@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// TODO Auto-generated method stub }/*** 更新apk* @param db*/private void createUpdateApk(SQLiteDatabase db){StringBuilder sb = new StringBuilder(" create table ").append(DBContants.TableApkUpdate.TABLE_NAME).append("(")// .append(DBContants.TableApkUpdate.ID).append(" Integer primary key autoincrement,")// .append(DBContants.TableApkUpdate.VERSION).append(" Integer, ")// .append(DBContants.TableApkUpdate.UpdatePackName).append(" text, ")// .append(DBContants.TableApkUpdate.MD5).append(" text, ")// .append(DBContants.TableApkUpdate.FileSize).append(" text); ");//执行创表语句 db.execSQL(sb.toString());} }
DBContants.java:
public class DBContants {//apk更新表public static class TableApkUpdate{public static final String TABLE_NAME="apkUpdate";public static final String ID="Id";public static final String VERSION="Version";public static final String UpdatePackName="UpdatePackName";public static final String MD5="MD5";public static final String FileSize="FileSize";} }
KeltiIntenface.java:
public class KeltiIntenface {public static String ipStr="newkelti.ip24.com.cn";public static String postStr="860";
//程序更新接口
public static String url="http://"+ipStr+":"+postStr+"/WebService/Pad_DataUpdate.asmx";
public static class FunctionName{//更新apkpublic static String GetCodeUpdate="GetCodeUpdate_v01";//"GetCodeUpdate";}}
YContants.java:
public class YContants {// 命名空间public static String namespace = "http://tempuri.org/"; }
Des.java:
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import android.annotation.SuppressLint;
import android.util.Base64;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
/*** 解密*/ public class Des { private Cipher c; // 密码器
private byte[] cipherByte;
private SecretKey deskey; // 密钥
private String keyString = "A3F2569DESJEIWBCJOTY45DYQWF68H1Y"; // 获得密钥的参数
/*** 加密* @param data* @return* @throws UnsupportedEncodingException*/public String createEncrypt(String data)throws UnsupportedEncodingException {if (data.equals("")) {return "";}try {byte[] buffData = data.getBytes("UTF8");byte[] dKey = deBase64(keyString);deskey = new javax.crypto.spec.SecretKeySpec(dKey, Algorithm);try {c = Cipher.getInstance(Algorithm);} catch (Exception e) {e.printStackTrace();}c.init(Cipher.ENCRYPT_MODE, deskey);cipherByte = c.doFinal(buffData);} catch (java.security.InvalidKeyException ex) {ex.printStackTrace();} catch (javax.crypto.BadPaddingException ex) {ex.printStackTrace();} catch (javax.crypto.IllegalBlockSizeException ex) {ex.printStackTrace();} catch (IOException e) {e.printStackTrace();}return Base64.encodeToString(cipherByte, Base64.DEFAULT);} }
UrlData2Json.java:
/*** 获取接口Json数据**/ public class UrlData2Json {/*** 返回一个JSONObject对象* * 说明:参数名数组和参数值数组要一一对应* * @param namespace 命名空间* @param methoName 方法名* @param url 接口地址* @param propertyName 参数名数组* @param propertyValue 参数值数组* @param networkExceptionListener 监听器* @return*/public static JSONObject getJSONObject(String namespace, String methoName,String url, String []propertyName,Object[] propertyValue,YNetworkExceptionListener networkExceptionListener) {try {SoapObject soapObject = new SoapObject(namespace, methoName);SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);if (propertyName!=null&&propertyValue!=null) {for (int i = 0; i < propertyName.length; i++) {// 带参数的方法调用,若调用无参数的,则无需此句soapObject.addProperty(propertyName[i],propertyValue[i]);// 添加参数 }}envelope.dotNet = true;envelope.setOutputSoapObject(soapObject);HttpTransportSE httpTranstation = new HttpTransportSE(url,YContants.CONNECTION_TIME);httpTranstation.call(namespace + methoName, envelope); Object result = envelope.getResponse();if (null==result) {return new JSONObject();}String str = (String) result.toString();// 获得请求的字符串 JSONObject jObject = new JSONObject(str);return jObject;} catch(ConnectException connectException){if (networkExceptionListener!=null) {networkExceptionListener.networkException();}connectException.printStackTrace();if(YContants.DEBUG) YLogUtil.printLog("connectException");}catch (SocketTimeoutException socketTimeoutException) {if (networkExceptionListener!=null) {networkExceptionListener.connectionTimeOut();}socketTimeoutException.printStackTrace();if(YContants.DEBUG) YLogUtil.printLog("socketTimeoutException");}catch (JSONException e) { if (networkExceptionListener!=null) {networkExceptionListener.JSONException();}e.printStackTrace();if(YContants.DEBUG) YLogUtil.printLog("JSONException");}catch (Exception e) {if (networkExceptionListener!=null) {networkExceptionListener.otherException();}e.printStackTrace();if(YContants.DEBUG) YLogUtil.printLog("Exception");} return null;} }
VersionUtil.java:
import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException;public class VersionUtil {public static String getVersionCode(Context context) {String version = "1.0";try {// 获取packagemanager的实例PackageManager packageManager = context.getPackageManager();// getPackageName()是你当前类的包名,0代表是获取版本信息 PackageInfo packInfo;packInfo = packageManager.getPackageInfo(context.getPackageName(),0);version = packInfo.versionName;} catch (NameNotFoundException e) {e.printStackTrace();}return version;} }
DecompressionZip.java:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipException;
import java.util.zip.ZipFile;
/*** 解压ZIP文件**/ public class DecompressionZip { /*** 解压功能* 将zipFile文件解压到folderPath目录* * @param zipFile 压缩文件* @param folderPath 存储路径* @return* @throws ZipException* @throws IOException*/@SuppressWarnings("rawtypes")public static int upZipFile(File zipFile, String folderPath) throws ZipException,IOException {ZipFile zfile = new ZipFile(zipFile);Enumeration zList = zfile.entries();//压缩文件的条目 ZipEntry ze = null;byte[] buf = new byte[1024];while (zList.hasMoreElements()) {ze = (ZipEntry) zList.nextElement();if (ze.isDirectory()) {//判断是否为一个目录 String dirstr = folderPath + ze.getName();dirstr = new String(dirstr.getBytes("8859_1"), "GB2312");File f = new File(dirstr);f.mkdir();continue;}OutputStream os = new BufferedOutputStream(new FileOutputStream(getRealFileName(folderPath, ze.getName())));InputStream is = new BufferedInputStream(zfile.getInputStream(ze));int readLen = 0;while ((readLen = is.read(buf, 0, 1024)) != -1) {os.write(buf, 0, readLen);}is.close();os.close();}zfile.close();return 0;} }
YLogUtil.java:
/*** 打印log**/ public class YLogUtil { private static final boolean LOG_DEBUG = true;//log输出的开关 public static <T> void printSpidLog(T log) {if(LOG_DEBUG){String logText="";try {String lineFormat = "类名:%s---方法名:%s---第%d行";StackTraceElement traceElement = Thread.currentThread().getStackTrace()[3];logText = String.format(lineFormat, traceElement.getFileName(),traceElement.getMethodName(), traceElement.getLineNumber());} catch (Exception e) {e.printStackTrace();logText="找不到出错位置";}Log.i("spid",logText+"---信息:"+log);}} }
转载于:https://www.cnblogs.com/wangchaozhangshu/p/5546002.html
更新android应用到最新版本相关推荐
- npm更新依赖包到最新版本
更新依赖包到最新版本 npm install 依赖包名称@latest -D 查看最新版本 npm info 依赖包名称 version(查看当前最新版本) npm info 依赖包名称 versio ...
- android qq版本6.6.1,手机QQ6.6.1有哪些更新内容 手机QQ最新版本详细介绍
手机QQ安卓版最新6.6.1已经出来了.有很多的小伙伴们发现,这版的QQ就是为了情侣打造的,当然只是开玩笑罢了.更新了一些新的东西给小伙伴们,文中为大家带来的就是手机QQ最新版本详细介绍. 目前,iO ...
- teamviewer11 android,teamviewer安卓最新版本
teamviewer安卓最新版本是一款可以远程控制别人手机的平台,在teamviewer安卓最新版本中你可以轻松的连接Windows和远程控制哦,而且teamviewer安卓最新版本在屏幕控制,高清语 ...
- 在Windows和macOS上更新Node.js到最新版本
有两种简单的升级方法: 1.从官方下载页面下载最新的Node.js版本,并安装新的Node.js版本. 2.安装n模块并在终端窗口内更新Node.js. 方法1:用安装程序更新Node.js 更新No ...
- 动态壁纸android,Android 十大最新版本动态壁纸大盘点
Typography Wall 是一款以透明雨滴做背景,同时能展示时钟.日期和电量信息的动态壁纸.这款透明雨滴时钟动态壁纸Typography Wall确实做的很漂亮,自从wpclock出来后,越来越 ...
- Android Studio 的最新版本 Arctic Fox创建项目 无法添加第三Maven仓库
最近升级到最新版本的Android Studio 发现无法添加第三方Maven仓库,在build.gradle(Project) 中发现只有buildscript {},缺少了之前的allprojec ...
- 升级Android Studio到最新版本,升级Gradle到最新,迁移Androidx之路。
随着Android手机的发展,Android系统版本的不断更新,迁移Androidx成了绕不开的步骤.如果是新项目,那 一切好说,但如果是老项目,坑死人不偿命(尤其是中途接手别人的项目的开发). 我是 ...
- 更新Ubuntu内核到最新版本
想起自己多年前玩Linux的时候知道了两个命令: sudo apt-get update sudo apt-get upgrade 以为是能够更新所有软件的,后来发现.系统还是不能够更新的. 那么,系 ...
- 【错误记录】AS 编译报错 ( Android Support plugin 版本太高 | 升级 Android Studio 到最新版本 )
文章目录 一.报错信息 二.解决方案 一.报错信息 从 GitHub 中 Clone 了一份代码 , 编译时报如下错误 ; Download https://services.gradle.org/d ...
最新文章
- JavaScript原型链以及Object,Function之间的关系
- matlab optimvar
- 执行全文索引时出现权限不足的解决方法
- js reduce实现中间件_js数组高阶方法reduce经典用法代码分享
- Cloud一分钟 | 误删生产数据库血案,顺丰高级工程师被开除;阿里巴巴暂停美国云计算扩张?阿里云总裁正式回应:“不会减少投入”...
- Luogu 3625 [APIO2009]采油区域
- c语言程序机试题及答案,C语言程序设计试题及答案解析(二)
- java消息推送怎么实现_PHP实现的消息实时推送功能
- C++11 变参模板
- 利用TestDriven.net和NUnit进行单元测试(转)
- 计算机基础知识集体备课,计算机基础知识集体备课.doc
- Vue毫秒计时器(开始计时)
- matlab编辑器风格定制,怎么使用135编辑器编辑出文艺清新的风格排版(附文艺排版素材)?...
- 计算机蓝屏重启,电脑蓝屏重启,详细教您电脑经常自动蓝屏重启怎么办
- 链塔区块链数据平台周报:新增富豪榜、项目点评、收藏等功能 | 链塔数据
- iOS-内购注意 沙盒二次验证
- 鼠标悬浮显示禁止图标
- 升级Windows10,安装程序无法正常启动无法初始化工作目录
- Methyltetrazine-DBCO,1802238-48-7该试剂可用于在无催化剂试剂的情况下,将含氮肽或蛋白质转化为四胺改性多肽或蛋白质
- Shell最最基础教程【案例讲解】【值得收藏系列】
热门文章
- virtuoso从电路图导入版图_基于Virtuoso 平台的单片射频收发系统电路仿真与版图设计...
- 设置input标签禁用_HTML option 标签
- php ajax 注册,非常实用的ajax用户注册模块
- 展开收起功能实现_Windows10自带的7大隐藏功能,个个都实用!
- 各厂商服务器存储设备默认密码大全
- 运维一定要懂的100个网络安全小知识
- 云原生体系下 Serverless 弹性探索与实践
- php随机数字总和固定,php 随机生成固定长度整数、各种服务器请求方法
- python实时监控_使用Python监控Linux系统
- java ftl 标签_Freemarker-标签使用