php apk包信息,php提取apk包信息
最近在項目中需要使用 php 提取 apk 包的主要信息如包名、應(yīng)用名稱、版本號、入口地址和應(yīng)用 Icon 等。安卓 apk 的大部分信息都保存在包內(nèi)的?AndroidManifest.xml 文件中,Icon 則保存在?drawable | drawable-hdpi | drawable-nodpi | drawable-ldpi | drawable-mdpi 這些文件夾中。
使用 php 讀取這些信息,網(wǎng)友大頭爸爸提供了一種做法:在服務(wù)器上安裝 java 包 和 反編譯工具 apktool ,通過 php 的 exec() 調(diào)用 java 命令來反編譯 apk 包,然后獲取 AndroidManifest.xml 文件的內(nèi)容,再根據(jù)正則表達式匹配出所需要的信息。提取圖標(biāo)則是通過遍歷?drawable | drawable-hdpi | drawable-nodpi | drawable-ldpi | drawable-mdpi 這些文件夾來獲取一個 size 最大的 Icon 。但是 反編譯 相當(dāng)耗時,不適用于實時程序。(源代碼見大頭爸爸 博客:http://www.voidcn.com/article/p-wkluywgx-gw.html)。
還有經(jīng)典的ApkParser,原理是使用 PHP 的 zip 功能函數(shù)直接解壓 apk 包而不需要外加 java 或命令行工具來獲取 AndroidManifest.xml 文件的內(nèi)容,然后也是根據(jù)正則表達式匹配出所需信息。這種方法執(zhí)行速度快但是得不到 Icon 。(源代碼見該方法作者?Katana's碎碎念 博客:)。
再后來看到了 ?cn王帥 的方案,覺得挺棒的。他這樣做:
1、用 aapt 讀取包信息
aapt dump badging ./xxx.apk
2、用 unzip 直接提取需要的圖標(biāo)文件
#解壓apk包中指定圖片
unzip ./xxx.apk res/drawable-mdpi/icon.png -d /tmp
#將解壓出來的圖片移到我們需要的位置
mv /tmp/res/drawable-mdpi/icon.png /tmp/temp.png
aapt 包含在 android sdk 中的 build-tools 文件夾,可以把這個文件拷到服務(wù)器上單獨使用,大小約1.2M。要記得用?chmod 賦予可執(zhí)行權(quán)限。還要注意的是,這個程序是32位環(huán)境的程序,64位系統(tǒng)運行可能需要額外安裝大概多個擴展包支持才能運行。aapt 命令執(zhí)行很快,PHP 調(diào)用這個命令可以實時返回數(shù)據(jù)。返回的數(shù)據(jù)中包含了包名、應(yīng)用名稱、 Icon 在 apk 包中的位置(類似 res/drawable-mdpi/icon.png)。返回的信息是純文本,不方便 PHP 直接使用,需要將其轉(zhuǎn)為數(shù)組。
因為 apk 本身就是 zip 文件重命名而已,所以無需改名,可以直接解壓。另外 unzip 可以指定只解壓壓縮包中某文件,也節(jié)省了很多資源。
class Service_Android {
/**
* 獲取Apk包信息
* 需要/usr/bin/aapt
*
* @param $apkFile
* @return array
*/
public function getApkInfo($apkFile) {
try {
exec('/usr/bin/aapt dump badging ' . $apkFile, $out, $return);
$apkInfo = array();
foreach($out as $line) {
$lineana = array();
$a = explode(":", $line);
$key = trim($a[0]);
$value = trim($a[1]);
preg_match_all('/((?P\S+)=)?\'(?P.*?)\'/', $value, $matches, PREG_SET_ORDER);
foreach($matches as $match) {
if ($match['key']) {
$lineana[$match['key']] = $match['value'];
} else {
$lineana[] = $match['value'];
}
}
$apkInfo[$key][] = $lineana;
}
//checkRet會把上面讀出來的配置整理一下
$ret = $this->checkRet($apkInfo);
} catch(Exception $e) {
echo $e->getMessage();
$ret = array();
}
return $ret;
}
/**
* 從Apk包中提取指定文件,并移到$toFile
*
* @param $apkFile apk文件
* @param $sourceFile apk文件中相應(yīng)文件路徑
* @param $toFile 輸出文件
* @return bool
*/
function getFileFromApk($apkFile, $sourceFile, $toDir, $toFile) {
exec("unzip {$apkFile} {$sourceFile} -d {$toDir}", $out, $return);
if (rename("{$toDir}{$sourceFile}", "{$toDir}{$toFile}")) {
exec("rm -rf {$toDir}/*");
return true;
} else {
exec("rm -rf {$toDir}/*");
return false;
}
}
/**
* 輔助函數(shù),處理Apk信息數(shù)組
*
* @param $info
* @return mixed
*/
function checkRet($info) {
foreach($info as $key => $lineana) {
if (is_array($lineana)) {
$info[$key] = $this->checkRet($lineana);
if (count($info[$key]) == 1) {
$info[$key] = current($info[$key]);
}
}
}
return $info;
}
}
使用方法:
include('Service_Android.class.php');
$apk = "b.apk";
$iconDir = '../icon/';
$iconFile = 'icon.png';
$android = new Service_Android();
$res = $android->getApkInfo($apk);
$android->getFileFromApk($apk, $res['application']['icon'], $iconDir , $iconFile);
另外,如果你恰巧真是64位系統(tǒng),使用過程可能會出現(xiàn)以下錯誤:
錯誤1:
-bash: /usr/bin/aapt: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
錯誤處理:
#查包
yum whatprovides ld-linux.so.2
#安裝
yum install -y glibc-2.12-1.149.el6_6.4.i686
錯誤2:
/usr/bin/aapt: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
錯誤處理:
#查包
yum whatprovides */libz.so.1
#安裝
yum install -y zlib-1.2.3-29.el6.i686
錯誤3:
/usr/bin/aapt: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory
錯誤處理:
yum install -y libstdc++
#查包
yum whatprovides libstdc++.so.6
#安裝
yum install -y libstdc++-4.4.7-11.el6.i686
其實上面的那些錯誤都是缺少 aapt 的擴展包導(dǎo)致的,使用命令:
#查看依賴
ldd /usr/bin/aapt
來查看缺失哪些包,把它們裝上就好了
總結(jié)
以上是生活随笔為你收集整理的php apk包信息,php提取apk包信息的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谈谈蓝牙跳频技术解决方案
- 下一篇: JavaScript贪吃蛇