使用common.js与对应的业务包 合成 业务bundle
24 | * Created by pukai on 16/12/6. 25 | */ 26 | public class BsdiffPatchUtil { 27 | public final static String COMMONJS = "common.js"; 28 | public final static String PACTH_PATH = "patchs"; 29 | public final static String BUSSINESS_PATH = "bussness"; 30 | public final static String patchExtensions = ".patch"; 31 | public final static String bundleExtensions = ".bundle"; 32 | public final static String BASE_SD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data/" + RNBsdiffApplication.sContext.getPackageName() + "/rn"; 33 | private String TAG = "BsdiffPatchUtil"; 34 | 35 | /** 36 | * 通过传递的moduleName 从 module.json 文件中找到对应的js文件名称,与common.js合成新的业务bundle; 37 | * example familyAddree:10001 -> patch/10001.patch+common.js -> 10001.bundle(RN setJSBundleFile 的文件) 38 | * 39 | * @param module 40 | * @return 成功 返回Bundle文件所在的文件路径 41 | * 失败 返回"" 42 | */ 43 | private String patch(RNModule module) { 44 | String modlueName = module.getModuleName(); 45 | String md5 = module.getMd5(); 46 | if (null == containsModule(modlueName)) { 47 | Log.e(TAG, modlueName + " not exists!"); 48 | } 49 | if (!isFileExists(BASE_SD_PATH + File.separator + COMMONJS)) { 50 | Log.e(TAG, "com" + " not exists!"); 51 | return ""; 52 | } 53 | if (!isFileExists(getSDCardPatchFilePath(modlueName))) { 54 | Log.e(TAG, modlueName + " not exists!"); 55 | return ""; 56 | } 57 | File file = new File(BASE_SD_PATH + File.separator + BUSSINESS_PATH); 58 | if (!file.exists()) { 59 | file.mkdirs(); 60 | } 61 | /** 62 | * 判断sd卡上是否存在业务的bundle 如果不存在或者 md5 与最新的md5不同则合成新的业务bundle 63 | * 64 | */ 65 | if (!isFileExists(getOutputFilePath(modlueName)) || !SignUtils.checkMd5(new File(getOutputFilePath(modlueName)), md5)) { 66 | if (PatchUtils.patch(BASE_SD_PATH + File.separator + COMMONJS, getOutputFilePath(modlueName), getSDCardPatchFilePath(modlueName)) == 0) { 67 | /** 68 | * 验证合成后的md5 是否与 最新的md5相同 检验合成是否成功 69 | */ 70 | if (SignUtils.checkMd5(getOutputFilePath(modlueName), md5)) { 71 | return getOutputFilePath(modlueName); 72 | } else { 73 | return ""; 74 | } 75 | } else { 76 | return ""; 77 | } 78 | } else { 79 | return ""; 80 | } 81 | } 82 | 83 | private boolean patchAll() { 84 | for (RNModule module : listModules) { 85 | if (null == patch(module)) { 86 | return false; 87 | } 88 | } 89 | return true; 90 | } 91 | 92 | private Runnable copyFileAndPatchAllRunnable = new Runnable() { 93 | @Override 94 | public void run() { 95 | init(); 96 | patchAll(); 97 | } 98 | }; 99 | private Runnable patchAllRunnable = new Runnable() { 100 | @Override 101 | public void run() { 102 | patchAll(); 103 | } 104 | }; 105 | 106 | private class PatchRunnable implements Runnable { 107 | private String moduleName; 108 | 109 | public PatchRunnable(String newModuleName) { 110 | moduleName = newModuleName; 111 | } 112 | 113 | @Override 114 | public void run() { 115 | if (listModules == null) { 116 | return; 117 | } 118 | for (RNModule module : listModules) { 119 | if (moduleName.equals(module.getModuleName())) { 120 | patch(module); 121 | } 122 | } 123 | } 124 | } 125 | 126 | /** 127 | * 复制asset下的全部文件并且合成所有的业务bundle 128 | */ 129 | public void copyFileAndPatchAllBundle() { 130 | new Thread(copyFileAndPatchAllRunnable).start(); 131 | } 132 | 133 | /** 134 | * 合成所有的bundle 135 | */ 136 | public void patchAllBundle() { 137 | new Thread(patchAllRunnable).start(); 138 | } 139 | 140 | /** 141 | * 合成指定moduleName的业务bundle 142 | * 143 | * @param moduleName 144 | */ 145 | public void patchBundle(String moduleName) { 146 | new Thread(new PatchRunnable(moduleName)).start(); 147 | } 148 | 149 | private String getSDCardPatchFilePath(String moduleName) { 150 | RNModule module = containsModule(moduleName); 151 | if (null != module) { 152 | return BASE_SD_PATH + File.separator + PACTH_PATH + File.separator + module.getModuleId() + patchExtensions; 153 | } else { 154 | return ""; 155 | } 156 | } 157 | 158 | 159 | public String getOutputFilePath(String moduleName) { 160 | RNModule module = containsModule(moduleName); 161 | if (null != module) { 162 | return BASE_SD_PATH + File.separator + BUSSINESS_PATH + File.separator + module.getModuleId() + bundleExtensions; 163 | } else { 164 | return ""; 165 | } 166 | } 167 | 168 | private RNModule containsModule(String str) { 169 | for (RNModule modlue : listModules) { 170 | if (str.equals(modlue.getModuleName()) || str.equals(modlue.getModuleId())) { 171 | return modlue; 172 | } 173 | } 174 | return null; 175 | } 176 | 177 | private boolean isFileExists(String path) { 178 | File file = new File(path); 179 | return file.exists(); 180 | } 181 | 182 | private static BsdiffPatchUtil bsdiffPatchUtil; 183 | 184 | public static BsdiffPatchUtil getInstance() { 185 | if (bsdiffPatchUtil == null) { 186 | bsdiffPatchUtil = new BsdiffPatchUtil(); 187 | } 188 | return bsdiffPatchUtil; 189 | } 190 | 191 | private List将json字符串转换成 list
238 | * 239 | * @param str 240 | * @return 241 | */ 242 | private List从assets目录中复制整个文件夹内容
258 | * 259 | * @param context Context 使用CopyFiles类的Context 260 | * @param oldPath String 原文件路径 如:rn 261 | * @param newPath String 复制后路径 如:xx:/bb/cc 262 | */ 263 | public boolean copyFilesFassets(Context context, String oldPath, String newPath) { 264 | try { 265 | String fileNames[] = context.getAssets().list(oldPath); 266 | if (fileNames.length > 0) { 267 | File file = new File(newPath); 268 | file.mkdirs(); 269 | for (String fileName : fileNames) { 270 | copyFilesFassets(context, oldPath + "/" + fileName, newPath + "/" + fileName); 271 | } 272 | } else { 273 | /** 274 | * 如果文件已经存在 且MD5 相同 跳过复制 275 | */ 276 | if (isFileExists(newPath) && SignUtils.getMd5ByFile(context.getAssets().open(oldPath)).equals(SignUtils.getMd5ByFile(new File(newPath)))) { 277 | Log.e("file", "exist " + newPath); 278 | } else { 279 | InputStream is = context.getAssets().open(oldPath); 280 | FileOutputStream fos = new FileOutputStream(new File(newPath)); 281 | byte[] buffer = new byte[1024]; 282 | int byteCount = 0; 283 | while ((byteCount = is.read(buffer)) != -1) { 284 | fos.write(buffer, 0, byteCount); 285 | } 286 | fos.flush(); 287 | is.close(); 288 | fos.close(); 289 | } 290 | } 291 | return true; 292 | } catch (Exception e) { 293 | e.printStackTrace(); 294 | return false; 295 | } 296 | } 297 | } 298 | -------------------------------------------------------------------------------- /AndroidReactNativeBsidffBundle/app/src/main/java/pk/com/reactnativebsidffbundle/HomeAddress.java: -------------------------------------------------------------------------------- 1 | package pk.com.reactnativebsidffbundle; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | import com.facebook.react.bridge.WritableMap; 7 | import com.facebook.react.bridge.WritableNativeMap; 8 | 9 | /** 10 | * @author pukai 11 | * @date 2016-11-23 12 | */ 13 | public class HomeAddress implements Parcelable { 14 | 15 | // {"addrId":43,"uid":6195148937236480,"cityId":348,"detailAddr":"贡古鲁克山口","lat":41.48715,"lng":78.6585,"selected":true,"createTime":1479722555000,"updateTime":1479722555000}, 16 | public String addrId; 17 | public String uid; 18 | public String cityId; 19 | 20 | public HomeAddress(String addrId, String detailAddr, boolean selected) { 21 | this.addrId = addrId; 22 | this.detailAddr = detailAddr; 23 | this.selected = selected; 24 | } 25 | 26 | public String detailAddr; 27 | public double lat; 28 | public double lng; 29 | public boolean selected; 30 | public String createTime; 31 | public String updateTime; 32 | 33 | public WritableMap getWritableMap(){ 34 | WritableMap writableMap = new WritableNativeMap(); 35 | writableMap.putString("addrId",addrId); 36 | writableMap.putString("uid",uid); 37 | writableMap.putString("cityId",cityId); 38 | writableMap.putString("detailAddr",detailAddr); 39 | writableMap.putDouble("lat",lat); 40 | writableMap.putDouble("lng",lng); 41 | writableMap.putBoolean("selected",selected); 42 | writableMap.putString("createTime",createTime); 43 | writableMap.putString("updateTime",updateTime); 44 | return writableMap; 45 | } 46 | @Override 47 | public int describeContents() { return 0; } 48 | 49 | 50 | @Override 51 | public void writeToParcel(Parcel dest, int flags) { 52 | dest.writeString(addrId); 53 | dest.writeString(uid); 54 | dest.writeString(cityId); 55 | dest.writeString(detailAddr); 56 | dest.writeDouble(lat); 57 | dest.writeDouble(lng); 58 | dest.writeByte((byte) (selected ? 1 : 0)); 59 | dest.writeString(createTime); 60 | dest.writeString(updateTime); 61 | } 62 | 63 | 64 | protected HomeAddress(Parcel in) { 65 | addrId = in.readString(); 66 | uid = in.readString(); 67 | cityId = in.readString(); 68 | detailAddr = in.readString(); 69 | lat = in.readDouble(); 70 | lng = in.readDouble(); 71 | selected = in.readByte() == 1; 72 | 73 | } 74 | 75 | 76 | 77 | public static final Creator