1、apk解析除了使用客户端利用aapt.exe、unzip.exe开发客户端解析外,还可以直接利用服务进行解析

/// <summary>
/// 从本地服务器获取APK文件并解析APK信息
/// </summary>
/// <param name="fileName">APK文件的完整路径</param>
/// <returns></returns>
[HttpPost, HttpGet, HttpOptions, CorsOptions]
public IActionResult DecodeAPK(string fileName)
{
if(fileName.IndexOf(".apk") == -1 && fileName.IndexOf(".zip") == -1)
{
return ErrorResult("未获取到APP上传路径!", 111111);
}
// 从服务器取文件
if(!string.IsNullOrWhiteSpace(fileName))
{
fileName = fileName.Replace(@"\", @" / ");
ApkInfo apk = new ApkInfo();
// 处理apk信息
try
apk = ReadAPK.ReadApkFromPath(fileName);
catch(Exception ex)
return ErrorResult("APP上传失败!--> APK解析失败,失败原因为:" + ex.Message, 111150);
return SuccessResult(apk, "APK解析成功");
}
else
return ErrorResult("APP上传失败!--> 从服务器获取APK文件失败,请联系网站管理员!", 111151);
}

2、ReadAPK  APK解析帮助类

/// <summary>
/// 读取APK信息
/// </summary>
public class ReadAPK
{
/// <summary>
/// 从上传apk的路径读取并解析apk信息
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public static ApkInfo ReadApkFromPath(string path)
{
byte[] manifestData = null;
byte[] resourcesData = null;
var manifest = "AndroidManifest.xml";
var resources = "resources.arsc";
//读取apk,通过解压的方式读取
using(var zip = ZipFile.Read(path))
{
using(Stream zipstream = zip[manifest].OpenReader())
{
//将解压出来的文件保存到一个路径(必须这样)
using(var fileStream = File.Create(manifest, (int) zipstream.Length))
{
manifestData = new byte[zipstream.Length];
zipstream.Read(manifestData, 0, manifestData.Length);
fileStream.Write(manifestData, 0, manifestData.Length);
}
}
using(Stream zipstream = zip[resources].OpenReader())
{
//将解压出来的文件保存到一个路径(必须这样)
using(var fileStream = File.Create(resources, (int) zipstream.Length))
{
resourcesData = new byte[zipstream.Length];
zipstream.Read(resourcesData, 0, resourcesData.Length);
fileStream.Write(resourcesData, 0, resourcesData.Length);
}
}
}
ApkReader apkReader = new ApkReader();
ApkInfo info = apkReader.extractInfo(manifestData, resourcesData);
return info;
}
}

3、APK解析类

注:此段代码解析APK时,若APK包含中文会极其的卡顿,建议上传前先用Npinyin重命名再次上传,至于原因已提交GitHub,暂未得到回复,所以先自己重命名再上传吧

Wrong Local header signature: 0xFF8

public class ApkReader
{
private static int VER_ID = 0;
private static int ICN_ID = 1;
private static int LABEL_ID = 2;
String[] VER_ICN = new String[3];
String[] TAGS = {
"manifest", "application", "activity"
};
String[] ATTRS = {
"android:", "a:", "activity:", "_:"
};
Dictionary < String, object > entryList = new Dictionary < String, object > ();
List < String > tmpFiles = new List < String > ();
public String fuzzFindInDocument(XmlDocument doc, String tag, String attr)
{
foreach(String t in TAGS)
{
XmlNodeList nodelist = doc.GetElementsByTagName(t);
for(int i = 0; i < nodelist.Count; i++)
{
XmlNode element = (XmlNode) nodelist.Item(i);
if(element.NodeType == XmlNodeType.Element)
{
XmlAttributeCollection map = element.Attributes;
for(int j = 0; j < map.Count; j++)
{
XmlNode element2 = map.Item(j);
if(element2.Name.EndsWith(attr))
{
return element2.Value;
}
}
}
}
}
return null;
}
private XmlDocument initDoc(String xml)
{
XmlDocument retval = new XmlDocument();
retval.LoadXml(xml);
retval.DocumentElement.Normalize();
return retval;
}
private void extractPermissions(ApkInfo info, XmlDocument doc)
{
ExtractPermission(info, doc, "uses-permission", "name");
ExtractPermission(info, doc, "permission-group", "name");
ExtractPermission(info, doc, "service", "permission");
ExtractPermission(info, doc, "provider", "permission");
ExtractPermission(info, doc, "activity", "permission");
}
private bool readBoolean(XmlDocument doc, String tag, String attribute)
{
String str = FindInDocument(doc, tag, attribute);
bool ret = false;
try
{
ret = Convert.ToBoolean(str);
}
catch
{
ret = false;
}
return ret;
}
private void extractSupportScreens(ApkInfo info, XmlDocument doc)
{
info.supportSmallScreens = readBoolean(doc, "supports-screens", "android:smallScreens");
info.supportNormalScreens = readBoolean(doc, "supports-screens", "android:normalScreens");
info.supportLargeScreens = readBoolean(doc, "supports-screens", "android:largeScreens");
if(info.supportSmallScreens || info.supportNormalScreens || info.supportLargeScreens) info.supportAnyDensity = false;
}
public ApkInfo extractInfo(byte[] manifest_xml, byte[] resources_arsx)
{
string manifestXml = string.Empty;
APKManifest manifest = new APKManifest();
try
{
manifestXml = manifest.ReadManifestFileIntoXml(manifest_xml);
}
catch(Exception ex)
{
throw ex;
}
XmlDocument doc = new XmlDocument();
doc.LoadXml(manifestXml);
return extractInfo(doc, resources_arsx);
}
public ApkInfo extractInfo(XmlDocument manifestXml, byte[] resources_arsx)
{
ApkInfo info = new ApkInfo();
VER_ICN[VER_ID] = "";
VER_ICN[ICN_ID] = "";
VER_ICN[LABEL_ID] = "";
try
{
XmlDocument doc = manifestXml;
if(doc == null) throw new Exception("Document initialize failed");
info.resourcesFileName = "resources.arsx";
info.resourcesFileBytes = resources_arsx;
// Fill up the permission field 不需要返回,注释
//extractPermissions(info, doc);
// Fill up some basic fields
info.minSdkVersion = FindInDocument(doc, "uses-sdk", "minSdkVersion");
info.targetSdkVersion = FindInDocument(doc, "uses-sdk", "targetSdkVersion");
info.versionCode = FindInDocument(doc, "manifest", "versionCode");
info.versionName = FindInDocument(doc, "manifest", "versionName");
info.packageName = FindInDocument(doc, "manifest", "package");
int labelID;
info.label = FindInDocument(doc, "application", "label");
if(info.label.StartsWith("@")) VER_ICN[LABEL_ID] = info.label;
else if(int.TryParse(info.label, out labelID)) VER_ICN[LABEL_ID] = String.Format("@{0}", labelID.ToString("X4"));
// Fill up the support screen field 不需要返回,注释
//extractSupportScreens(info, doc);
if(info.versionCode == null) info.versionCode = fuzzFindInDocument(doc, "manifest", "versionCode");
if(info.versionName == null) info.versionName = fuzzFindInDocument(doc, "manifest", "versionName");
else if(info.versionName.StartsWith("@")) VER_ICN[VER_ID] = info.versionName;
String id = FindInDocument(doc, "application", "android:icon");
if(null == id)
{
id = fuzzFindInDocument(doc, "manifest", "icon");
}
if(null == id)
{
Debug.WriteLine("icon resId Not Found!");
return info;
}#
region 获取APK名称的代码暂时注释, 运行时间太卡顿
// Find real strings
if(!info.hasIcon && id != null)
{
if(id.StartsWith("@android:")) VER_ICN[ICN_ID] = "@" + (id.Substring("@android:".Length));
else VER_ICN[ICN_ID] = String.Format("@{0}", Convert.ToInt32(id).ToString("X4"));
List < String > resId = new List < String > ();
for(int i = 0; i < VER_ICN.Length; i++)
{
if(VER_ICN[i].StartsWith("@")) resId.Add(VER_ICN[i]);
}
ApkResourceFinder finder = new ApkResourceFinder();
info.resStrings = finder.processResourceTable(info.resourcesFileBytes, resId);
if(!VER_ICN[VER_ID].Equals(""))
{
List < String > versions = null;
if(info.resStrings.ContainsKey(VER_ICN[VER_ID].ToUpper())) versions = info.resStrings[VER_ICN[VER_ID].ToUpper()];
if(versions != null)
{
if(versions.Count > 0) info.versionName = versions[0];
}
else
{
throw new Exception("VersionName Cant Find in resource with id " + VER_ICN[VER_ID]);
}
}
List < String > iconPaths = null;
if(info.resStrings.ContainsKey(VER_ICN[ICN_ID].ToUpper())) iconPaths = info.resStrings[VER_ICN[ICN_ID].ToUpper()];
if(iconPaths != null && iconPaths.Count > 0)
{
info.iconFileNameToGet = new List < String > ();
info.iconFileName = new List < string > ();
foreach(String iconFileName in iconPaths)
{
if(iconFileName != null)
{
if(iconFileName.Contains(@"/"))
{
info.iconFileNameToGet.Add(iconFileName);
info.iconFileName.Add(iconFileName);
info.hasIcon = true;
}
}
}
}
else
{
throw new Exception("Icon Cant Find in resource with id " + VER_ICN[ICN_ID]);
}
if(!VER_ICN[LABEL_ID].Equals(""))
{
List < String > labels = null;
if(info.resStrings.ContainsKey(VER_ICN[LABEL_ID])) labels = info.resStrings[VER_ICN[LABEL_ID]];
if(labels.Count > 0)
{
info.label = labels[0];
}
}
}#
endregion
}
catch(Exception e)
{
throw e;
}
return info;
}
private void ExtractPermission(ApkInfo info, XmlDocument doc, String keyName, String attribName)
{
XmlNodeList usesPermissions = doc.GetElementsByTagName(keyName);
if(usesPermissions != null)
{
for(int s = 0; s < usesPermissions.Count; s++)
{
XmlNode permissionNode = usesPermissions.Item(s);
if(permissionNode.NodeType == XmlNodeType.Element)
{
XmlNode node = permissionNode.Attributes.GetNamedItem(attribName);
if(node != null) info.Permissions.Add(node.Value);
}
}
}
}
private String FindInDocument(XmlDocument doc, String keyName, String attribName)
{
XmlNodeList usesPermissions = doc.GetElementsByTagName(keyName);
if(usesPermissions != null)
{
for(int s = 0; s < usesPermissions.Count; s++)
{
XmlNode permissionNode = usesPermissions.Item(s);
if(permissionNode.NodeType == XmlNodeType.Element)
{
XmlNode node = permissionNode.Attributes.GetNamedItem(attribName);
if(node != null) return node.Value;
}
}
}
return null;
}
}

4、APK解析返回类

public class ApkInfo
{
/// <summary>
/// APK名称
/// </summary>
public string label
{
get;
set;
}
/// <summary>
/// APK版本号
/// </summary>
public string versionName
{
get;
set;
}
/// <summary>
/// APK版本编号
/// </summary>
public string versionCode
{
get;
set;
}
/// <summary>
/// APK支持的最小SDK版本
/// </summary>
public string minSdkVersion
{
get;
set;
}
/// <summary>
/// APK的目标SDK版本
/// </summary>
public string targetSdkVersion
{
get;
set;
}
/// <summary>
/// APK包名称
/// </summary>
public string packageName
{
get;
set;
}
public static int FINE = 0;
public static int NULL_VERSION_CODE = 1;
public static int NULL_VERSION_NAME = 2;
public static int NULL_PERMISSION = 3;
public static int NULL_ICON = 4;
public static int NULL_CERT_FILE = 5;
public static int BAD_CERT = 6;
public static int NULL_SF_FILE = 7;
public static int BAD_SF = 8;
public static int NULL_MANIFEST = 9;
public static int NULL_RESOURCES = 10;
public static int NULL_DEX = 13;
public static int NULL_METAINFO = 14;
public static int BAD_JAR = 11;
public static int BAD_READ_INFO = 12;
public static int NULL_FILE = 15;
public static int HAS_REF = 16;
// 其他不返回属性权限、其他资源文件等等
public List < String > Permissions;
public List < String > iconFileName;
public List < String > iconFileNameToGet;
public List < String > iconHash;
public String resourcesFileName;
public byte[] resourcesFileBytes;
public bool hasIcon;
public bool supportSmallScreens;
public bool supportNormalScreens;
public bool supportLargeScreens;
public bool supportAnyDensity;
public Dictionary < String, List < String >> resStrings;
public Dictionary < String, String > layoutStrings;
public static bool supportSmallScreen(byte[] dpi)
{
if(dpi[0] == 1) return true;
return false;
}
public static bool supportNormalScreen(byte[] dpi)
{
if(dpi[1] == 1) return true;
return false;
}
public static bool supportLargeScreen(byte[] dpi)
{
if(dpi[2] == 1) return true;
return false;
}
//public byte[] getDPI()
//{
// byte[] dpi = new byte[3];
// if (this.supportAnyDensity)
// {
// dpi[0] = 1;
// dpi[1] = 1;
// dpi[2] = 1;
// }
// else
// {
// if (this.supportSmallScreens)
// dpi[0] = 1;
// if (this.supportNormalScreens)
// dpi[1] = 1;
// if (this.supportLargeScreens)
// dpi[2] = 1;
// }
// return dpi;
//}
public ApkInfo()
{
hasIcon = false;
supportSmallScreens = false;
supportNormalScreens = false;
supportLargeScreens = false;
supportAnyDensity = true;
versionCode = null;
versionName = null;
iconFileName = null;
iconFileNameToGet = null;
Permissions = new List < String > ();
}
private bool isReference(List < String > strs)
{
try
{
foreach(String str in strs)
{
if(isReference(str)) return true;
}
}
catch(Exception e)
{
throw e;
}
return false;
}
private bool isReference(String str)
{
try
{
if(str != null && str.StartsWith("@"))
{
int.Parse(str, System.Globalization.NumberStyles.HexNumber);
return true;
}
}
catch(Exception e)
{
throw e;
}
return false;
}
}

以上就是.net core 从(本地)服务器获取APK文件并解析APK信息的介绍,做此记录,如有帮助,欢迎点赞关注收藏!

.net core 从(本地)服务器获取APK文件并解析APK信息的更多相关文章

  1. [Android Pro] 查看 keystore文件的签名信息 和 检查apk文件中的签名信息

    1: 查看 keystore文件的签名信息 keytool -list -v -keystore keystoreName -storepass keystorePassword 2: 检查apk文件 ...

  2. sublime text3在指定浏览器上本地服务器(localhost)运行文件(php)

    昨天在使用sublime text3时,发现能在本地服务器上运行php文件,于是百度了一下有关知识, 终于成功了,今天总结一下. 首先要让sublime text3 出现侧边栏sidebar,不会的可 ...

  3. Ajax——从服务器获取各种文件

    ajax.js内容 function ajax(url,fnWin,fnFaild){ //1.创建ajax对象 var xhr = window.XMLHttpRequest ? new XMLHt ...

  4. php自定义函数: 下载本地服务器的大文件

    // 使用方法 $file_path = './a.zip'; // 只能是本地服务器文件, 多大的文件都支持!! down_file($file_path); // 函数参数: 服务器文件路径,下载 ...

  5. [转]sublime text3在指定浏览器上本地服务器(localhost)运行文件(php)

    昨天在使用sublime text3时,发现能在本地服务器上运行php文件,于是百度了一下有关知识, 终于成功了,今天总结一下. 首先要让sublime text3 出现侧边栏sidebar,不会的可 ...

  6. 使用node建立本地服务器访问静态文件

    最终目录结构 demo │ node_modules └───public │ │ index.html │ │ index.css │ └───index.js └───server.js 一.使用 ...

  7. sublime text3:sublime text3本地服务器方式运行文件

    网址:https://blog.csdn.net/md1688/article/details/70562381 1.Ctrl + Shift +P,启动Sublime Text的命令行(如果没有需要 ...

  8. java从远程服务器获取PDF文件并后台打印(使用pdfFox)

    一.java原生方式打印PDF文件 正反面都打印,还未研究出只打印单面的方法,待解决 public static void printFile(String path) throws Exceptio ...

  9. Android从网络中获取xml文件并解析数据

    public class XmlwebData { @SuppressLint("UseValueOf") public static List<Person> get ...

  10. iOS - 音乐播放器需要获取音乐文件的一些数据信息(封装获取封面图片的类)

    // // AVMetadataInfo.h // AVMetadata // // Created by Wengrp on 15/10/27. // Copyright © 2015年 Wengr ...

随机推荐

  1. GAMES101课程 作业6 源代码概览

    GAMES101课程 作业6 源代码概览 Written by PiscesAlpaca(双鱼座羊驼) 一.概述 本篇将从main函数为出发点,按照各cpp文件中函数的调用顺序和层级嵌套关系,简单分析 ...

  2. polkit(ploicykit)特权提升漏洞解决方案

    一.[概述] polkit 的 pkexec 存在本地权限提升漏洞,已获得普通权限的攻击者可通过此漏洞获取root权限,漏洞利用难度低. pkexec是一个Linux下Polkit里的setuid工具 ...

  3. 图文详解在VMware Workstation 16 PRO虚拟机上安装Ubuntu 22.04.5 linux系统

    一.下载Ubuntu linux系统镜像 机构 下载地址 官网地址 https://cn.ubuntu.com/download 南京大学 https://mirrors.nju.edu.cn/ubu ...

  4. 重要内置函数、常见内置函数、可迭代对象、迭代器对象、for循环的本质、异常捕获处理

    重要内置函数 #zip拉链 zip 函数是可以接收多个可迭代对象,然后把每个可迭代对象中的第i个元素组合在一起,形成一个新的迭代器,类型为元组. l1 = [11, 22, 33] l2 = ['a' ...

  5. 在Windows模拟器中使用LVGL8.3

    引言 LVGL是一个跨平台.轻量级.易于移植的图形库.也因其支持大量特性和其易于裁剪,配置开关众多,且版本升级较快,不同版本之间存在一定的差异性,相关的使用教程有一定的滞后性,由于缺少最新版本的中文教 ...

  6. 谈谈我的「数字文具盒」 - NextCloud

    接下来两篇主要谈论 Nextcloud 和 Obsidian,因为篇幅较长,所以单出罗列出来.本文主要介绍 Nextcloud 以及使用中的技巧和心得体会. Nextcloud Nextcloud 是 ...

  7. 【day01】redis

    〇.思维导图 1.解决缓存数据库双写不一致 延迟双删(中间sleep一段时间)--写性能下降 内存队列:同一个key(线程)的所有操作丢到队列,串行化执行--实现麻烦&大量内存队列,队列宕机 ...

  8. 【离线数仓】Day02-用户行为数据仓库:分层介绍、环境搭建(hive、tez)、LZO压缩、建表查询导入加索引、编写脚本

    一.数仓分层概念 1.为什么要分层 ODS:原始数据层 DWD层:明细数据层 DWS:服务数据层 ADS:数据应用层 2.数仓分层 3.数据集市与数据仓库概念 4.数仓命名规范 ODS层命名为odsD ...

  9. 基础css样式

    目录 css层叠样式表 css选择器 伪类选择器 选择器生效优先级 css字体颜色背景 设置宽高 边框 display属性 div盒子模型 float漂浮 溢出overflow 定位(position ...

  10. 同步与异步 multiprocessing 进程对象多种方法

    目录 同步与异步 阻塞与非阻塞 综合使用 创建进程的多种方式 前言 windows系统创建进程的问题(重要) multiprocessing模块之Process 展现异步 创建进程的方式(一):使用P ...