鸿蒙hap包通过接口下载安装
接口下载安装鸿蒙、java、鸿蒙、华为
·
鸿蒙hap下载安装
方式1:描述文件下载
常规方法,将json5安装描述文件放到服务器上,访问json5文件的地址必须是https开头。
方式2:接口下载
通过接口文件流的形式返回
最最最重要的一点是接口必须支持分片下载,通过nginx的请求可以看出,访问json文件时,会先发HEAD请求,再发GET请求。访问安装包下载接口时也是先发HEAD请求,会根据包大小,来分发几次GET请求。
-
访问json5文件
@RequestMapping(value = "install/{id}/harmony.json5", method = {RequestMethod.GET,RequestMethod.HEAD})
public void downJson5File(HttpServletRequest request, HttpServletResponse response,
@PathVariable("id") String id) {
OutputStream os = null;
InputStream in = null;
String method = request.getMethod();
logger.info("请求方式:{}",method);
try {
//id是数据库主键,查询数据库,获取从后管配置的安装信息
Map installInfo = "通过id查询具体的安装信息";
//鸿蒙端下载信息
String sysIcon = String.valueOf(installInfo.get("SYSICON"));// 系統图标
String version = String.valueOf(installInfo.get("VERSION"));// 版本
String bundleId = String.valueOf(installInfo.get("BUNDLEID"));// 客户端package名称
String packageHash = String.valueOf(installInfo.get("PACKAGEHASH"));// 安装包hash值
String versionCode = String.valueOf(installInfo.get("VERSIONCODE"));// 441
// 组装
Map<String, String> harmonyMap = new HashMap<String, String>();
harmonyMap.put("bundleName", bundleId);
harmonyMap.put("packageHash", packageHash);
harmonyMap.put("versionName", version);
harmonyMap.put("versionCode", versionCode);
harmonyMap.put("sysIcon", sysIcon);
//这里拼接的是下面下载hap的接口地址,https开头
harmonyMap.put("packageUrl", "https://xxx/xxx/" + "install/"+ id + "/hapDownload.hap");
// 指定是二进制流
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
// 文件流
String jsonStr = AppDownloadUtil.generateHarmonyContent(harmonyMap);
in = new ByteArrayInputStream(jsonStr.getBytes());
os = response.getOutputStream();
int len = 0;
byte[] buffer = new byte[4096];
while ((len = in.read(buffer)) > 0) {
os.write(buffer, 0, len);
}
os.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 生成鸿蒙.json5文件
* @param map
* @return
*/
public static String generateHarmonyContent(Map<String, String> map) {
Map jsonMap = new LinkedHashMap<>();
//包名
String bundleName = map.get("bundleName");
//安装地址
String packageUrl = map.get("packageUrl");
//安装包hash值
String packageHash = map.get("packageHash");
//安装包版本号
String versionName = map.get("versionName");
//鸿蒙code 421
String versionCode = map.get("versionCode");
//系统图标
String sysIcon = map.get("sysIcon");
//根节点
Map appLinkMap = new LinkedHashMap<>();
appLinkMap.put("bundleName", bundleName);
appLinkMap.put("bundleType", "app");
appLinkMap.put("versionCode", Integer.valueOf(versionCode));
appLinkMap.put("versionName", versionName);
appLinkMap.put("label", "测试");
appLinkMap.put("deployDomain", domain);
//icon节点
Map iconLinkMap = new LinkedHashMap<>();
iconLinkMap.put("normal", sysIcon );
iconLinkMap.put("large", sysIcon);
appLinkMap.put("icons", iconLinkMap);
appLinkMap.put("minAPIVersion", "5.0.0(12)");
appLinkMap.put("targetAPIVersion", "5.0.0(12)");
//modules模块
List modulesList = new ArrayList<>();
Map modulesLinkMap = new LinkedHashMap<>();
modulesLinkMap.put("name", "entry");
modulesLinkMap.put("type", "entry");
//modules下的deviceType模块
List deviceTypesList = new ArrayList<>();
deviceTypesList.add("tablet");
deviceTypesList.add("phone");
modulesLinkMap.put("deviceTypes", deviceTypesList);
modulesLinkMap.put("packageUrl", packageUrl);
modulesLinkMap.put("packageHash", packageHash);
modulesList.add(modulesLinkMap);
appLinkMap.put("modules", modulesList);
jsonMap.put("app", appLinkMap);
String jsonStr = JSONObject.toJSONString(jsonMap);
logger.info("json5:{}",jsonStr);
return jsonStr;
}
-
下载hap接口
//controller中同时支持HEAD、GET接口请求
@RequestMapping(value = "insall/{id}/hapDownload.hap", method = {RequestMethod.GET,RequestMethod.HEAD})
public void hapDownloadFile(HttpServletRequest request, HttpServletResponse response,@PathVariable("id") String id) {
OutputStream os = null;
InputStream is = null;
String method = request.getMethod();
logger.info("请求方式:{}",method);
try {
Map installInfo = "根据id查询安装信息"
String sysCode = String.valueOf(installInfo.get("SYSCODE"));// 系統編碼
String platform = String.valueOf(installInfo.get("PLATFORM"));// 下载的类型
String version = String.valueOf(installInfo.get("VERSION"));// 版本
name = String.valueOf(installInfo.get("NAME"));// 下载的包名称
// 拼接路径,安装包在服务器上的全路径,/home/app/xxx.hap,根据自己服务器拼写
String downUrl = "/home/app/xxx.hap";
logger.info("下载路径:{}",downUrl);
//获取文件
File file = new File(downUrl);
//文件大小
int fSize = (int) file.length();
logger.info("安装包大小:{}",fSize);
// 指定回复的内容为attachment,下载并保存到设备上,并伴随对话框
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + name + "\"");
//指定单位
response.setHeader(HttpHeaders.ACCEPT_RANGES,"bytes");
response.setHeader("filename",name);
//下面是分片的操作,设置变量,分别是开始位置,最后结束位置,总数
long pos = 0,last = fSize-1,sum = 0;
String range = request.getHeader("Range");
if(null != range) {
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
//请求头里面的range 0-6578945
String numberRange = range.replaceAll("bytes=","");
String[] strRange = numberRange.split("-");
logger.info("请求range:{},截取之后的range:{}",range,numberRange);
if(strRange.length == 2) {
pos = Long.parseLong(strRange[0].trim());
last = Long.parseLong(strRange[1].trim());
if(last > fSize -1 ) {
last = fSize -1;
}
}else{
pos = Long.parseLong(numberRange.replaceAll("-","").trim());
}
}
//计算待下载文件
long rangeLength = last - pos + 1;
logger.info("本次文件大小:{}",rangeLength);
String contentRange = "bytes " + pos + "-" + last + "/" + fSize;
logger.info("下载的范围:{}",contentRange);
response.setHeader(HttpHeaders.CONTENT_RANGE,contentRange);
// 告知文件大小,影响浏览器下载进度条
response.setHeader(HttpHeaders.CONTENT_LENGTH, String.valueOf(rangeLength));
// 指定是二进制流
response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
// 文件流
os = new BufferedOutputStream(response.getOutputStream());
is = new BufferedInputStream(new FileInputStream(file));
is.skip(pos);
byte[] buffer = new byte[4096];
int length = 0;
while(sum < rangeLength) {
int readLength = (int)(rangeLength - sum );
length = is.read(buffer,0, readLength <= buffer.length ? readLength : buffer.length);
sum +=length;
os.write(buffer, 0, length);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
-
总结
不管是json5的接口还是下载hap的接口,都要用对应的名称结尾,负责华为那边可能都不会来访问你给他的地址,json5文件的相关信息一定要配置正确。
更多推荐
所有评论(0)