在服务器上安装android-apktool,我们服务器是CentOS5.5,所以我选择的包是:apktool-install-linux-2.2_r01-1.tar.bz2 。再执行安装(参考安装说明)
#linux
1. cd /usr/local/bin
2. curl -O https://connortumbleson.com/apktool/googlecode/apktool-install-linux-2.2_r01-1.tar.bz2 下载apktool
3. sudo tar jxvf apktool-install-linux-2.2_r01-1.tar.bz2 解压(这里解压需要有root权限)
利用PHP的函数exec去执行aapt命令。
一般PHP环境,默认是不允许exec,shell_exec等shell命令函数的。所以我们得更改php.ini配置文件。请注意:开启exec函数功能,可能会对服务器安全有比较大的隐患,所以请自行决定是否可行。
#Linux
测试aapt命令是否可用。执行命令:
$ aapt d badging test.apk
1. <?php
2. exec ( "/usr/bin/sudo /usr/local/bin/aapt d badging /var/www/test/test.apk>info.txt 2>&1" , $out , $return );
3. //用root 去执行aapt命令,把输出的信息写入info.txt文件,下面我们要用用正则取输出的相关数据
4. var_dump( $out );
5. var_dump( $return );
6. ?>
注意
在这里请一定注意三点:
1.你的WEB用户权限是否有执行aapt的权限,如果没有,请用visudo修改sudo的配置文件,在最后加入这样一行:
www ALL=NOPASSWD:/usr/local/bin/aapt (让www用户以root权限来执行aapt,NOPASSWD代表 sudo 时候不用输入密码). vi /etc/sudoers (或在宝塔上改)
2.PHP脚本执行sudo时,可能会报出:sudo: sorry, you must have a tty to run sudo错误,提示需要一个终端才能执行sudo.此时解决办法,用visduo命令,找到Defaults requiretty这行前面加#号它注解掉。
3.需要用来处理apk的图标
7z 解压(命令:yum install p7zip p7zip-plugins)
获取前端传过来的文件,判断安卓还是ios
public function upload()
{
$method = $_SERVER['REQUEST_METHOD'];
if ($method == "POST") {
// 获取项目中uploads的地址
$proPath = explode('DownDot/', __DIR__);
$path = $proPath[0] . 'DownDot/uploads';
// 配置相关的信息
$config['upload_path'] = $path;
$config['allowed_types'] = '*';
$config['file_name'] = uniqid();
$this->load->library('upload', $config);
if (!$this->upload->do_upload('file')) {
$error = array('error' => $this->upload->display_errors());
echo $error['error'];
} else {
$data = $this->upload->data();
$fileSize = filesize($data['full_path']);
// 获取当前时间
date_default_timezone_set('prc');
$create_time = date('y-m-d H:i:s', time());
$info = array();
//安卓上传
if ($data['file_ext'] == '.apk') {
$this->load->helper('apkinfo');
$info = PopApkInfo($data['full_path']);
} elseif ($data['file_ext'] == '.ipa') {
$this->load->helper('ipainfo');
$info = ipaInfo($data);
}
// 上传文件到OSS
$icon = $info['icon'];
$name = $info['lable'];
$pkg_name = $info['sys_name'];
$version = $info['version'];
$build_num = $info['version_code'];
}
}
}
安卓(apk)解析
function PopApkInfo($apk_file)
{
// $apk_file = '/www/wwwroot/www.***.top/public/uploads/demo.apk';
// $_cmd = '/Users/mac/Library/Android/sdk/build-tools/29.0.2/aapt dump badging '.$apk_file.' ls 2>&1';
$path = app()->getRootPath().'public/uploads';
$_cmd = '/usr/bin/sudo /usr/local/bin/aapt d badging '.$apk_file;
exec($_cmd,$out, $return);
$temp_path = $path.'/icon/'.md5($apk_file).'/';
$relative_path= 'uploads/icon/'.md5($apk_file);
if($return == 0)
{
if (!file_exists($temp_path)) {
mkdir($temp_path,0777,true);
}
$str_out = implode("\n", $out);
$out = null;
#icon
$pattern_icon = "/icon='(.+)'/isU";
preg_match($pattern_icon, $str_out, $m);
$info['icon'] = $m[1];
if($info['icon'])
{
$command = '/usr/bin/7z e '. $apk_file . ' -y -aos -o' . $temp_path . ' ' . $info['icon'];
exec($command);
$barPosition=strrpos($info['icon'],'/');
if($barPosition != false) {
$iconPath=substr($info['icon'], $barPosition);
} else {
$iconPath=$info['icon'];
}
$info['icon'] = $relative_path . $iconPath;
}
#对外显示名称
$pattern_name = "/application: label='(.*)'/isU";
preg_match($pattern_name, $str_out,$m);
$info['lable']=$m[1];
#内部名称,软件唯一的
$pattern_sys_name = "/package: name='(.*)'/isU";
preg_match($pattern_sys_name, $str_out,$m);
$info['sys_name']=$m[1];
#内部版本名称,用于检查升级
$pattern_version_code = "/versionCode='(.*)'/isU";
preg_match($pattern_version_code, $str_out,$m);
$info['version_code']=$m[1];
#对外显示的版本名称
$pattern_version = "/versionName='(.*)'/isU";
preg_match($pattern_version, $str_out,$m);
$info['version']=$m[1];
$info['apk_info'] = $str_out;
$info['type'] = 'and';
return $info;
}
return false;
}
ios 解析需要用到第三方工具 CFPropertyList
function ipaInfo($ipa_file) {
//var_dump($ipa_file);
// 获取文件地址
$filePath= $ipa_file['full_path'];
// 获取项目地址
$filesPath = FCPATH.'uploads';
// 解压文件
$_cmd = 'unzip -u '.$filePath.' -d /tmp ';
exec($_cmd,$output,$return_var);
//查询文件.app并去掉后缀
$fileName = scandir('/tmp/Payload');
$newFileName = $fileName[2];
$file_name = explode('.app',$newFileName);
$newFile_name = $file_name[0];
$_rename = 'mv /tmp/Payload/'.$newFileName.' /tmp/Payload/'.$newFile_name;
exec($_rename,$out,$return);
// 加载插件
$path = FCPATH.'application/';
require_once($path.'third_party/CFPropertyList/CFType.php');
require_once($path.'third_party/CFPropertyList/CFArray.php');
require_once($path.'third_party/CFPropertyList/CFBoolean.php');
require_once($path.'third_party/CFPropertyList/CFData.php');
require_once($path.'third_party/CFPropertyList/CFDate.php');
require_once($path.'third_party/CFPropertyList/CFDictionary.php');
require_once($path.'third_party/CFPropertyList/CFNumber.php');
require_once($path.'third_party/CFPropertyList/CFString.php');
require_once($path.'third_party/CFPropertyList/CFTypeDetector.php');
require_once($path.'third_party/CFPropertyList/CFUid.php');
require_once($path.'third_party/CFPropertyList/IOException.php');
require_once($path.'third_party/CFPropertyList/PListException.php');
require_once($path.'third_party/CFPropertyList/CFBinaryPropertyList.php');
require_once($path.'third_party/CFPropertyList/CFPropertyList.php');
if (($return_var == 0 || $return_var == 1) && $return == 0) {
$content =file_get_contents('/tmp/Payload/'.$newFile_name.'/Info.plist');
$plist = new \CFPropertyList\CFPropertyList();
$plist->parse($content);
$data = $plist->toArray();
$info['icon'] = '';
$info['lable'] = $data['CFBundleName'];
$info['sys_name'] = $data['CFBundleIdentifier'];
$info['version'] = $data['CFBundleShortVersionString'];
$info['version_code'] = $data['CFBundleVersion'];
// 获取图标
$CFBundleIcons = $data['CFBundleIcons']['CFBundlePrimaryIcon']['CFBundleIconFiles'];
//['CFBundleIcons']
$iconName = end($CFBundleIcons);
$icon_name1 = '/tmp/Payload/'.$newFile_name.'/'.$iconName.'.png';
$icon_name2 = '/tmp/Payload/'.$newFile_name.'/'.$iconName.'@2x.png';
$md5 = md5($filePath);
$temp_path = $filesPath.'/icon/'.$md5.'/';
if (!file_exists($temp_path)) {
mkdir($temp_path,0777,true);
}
require_once($path . '/helpers/parsers_helper.php');
$filename = null;
if (file_exists($icon_name1)) {
$filename = $icon_name1; //需要解密的文件路径
}elseif (file_exists($icon_name2)){
$filename = $icon_name2; //需要解密的文件路径
}
if ($filename !== null) {
$newFilename = 'uploads/icon/'.$md5.'/'.$iconName.'.png'; //解密后的文件路径
Parsers::fix($filename,$newFilename);
$info['icon'] = 'uploads/icon/'.$md5.'/'.$iconName.'.png';
}
$info['type'] = 'ios';
exec('rm -rf /tmp/Payload');
return $info;
}
exec('rm -rf /tmp/Payload');
return false;
}
下载文件
/**
* @param $url 下载地址
* @param string $publicDir 文件存放地址
* @param string $filename 文件名称
* @param int $type
* @return array|bool
*/
function getDownload($url, $publicDir = '', $fileName = '', $type = 0)
{
// $res = getDownload('http://www.***.top/uploads/demo2.apk','apktemp/demo.apk','demo.apk');
//获取文件路径
$publicDir = app()->getRootPath() . 'public/uploads/' . $publicDir;
$newOneDir = substr($publicDir, 0, strrpos($publicDir, "/"));
if (trim($url) == '') {
return false;
}
//检验访问url是否有效
$array = get_headers($url, 1);
if (!preg_match('/200/', $array[0])) {
return false;
}
// if (trim($publicDir) == '') {
// return false;
// }
//创建保存目录
if (!file_exists($newOneDir) && !mkdir($newOneDir, 0777, true)) {
return false;
}
//原来文件存在则删除
// if (file_exists($save_dir)) {
// unlink($save_dir);
// }
//获取远程文件所采用的方法
if ($type) {
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$content = curl_exec($ch);
curl_close($ch);
} else {
ob_start();
readfile($url);
$content = ob_get_contents();
ob_end_clean();
}
// $size = strlen($content);
//文件大小
$fp2 = @fopen($publicDir, 'a');
fwrite($fp2, $content);
fclose($fp2);
unset($content, $url);
return array(
'file_name' => $fileName,
'save_path' => $publicDir,
// 'file_size' => $size
);
}