|
|
|
|
<?php
|
|
|
|
|
namespace Base\Service;
|
|
|
|
|
|
|
|
|
|
use Base\Model\PromoteModel;
|
|
|
|
|
use Base\Model\ApplyModel;
|
|
|
|
|
use Base\Tool\Base62;
|
|
|
|
|
use Base\Tool\PlistDemo;
|
|
|
|
|
use GuzzleHttp\Client;
|
|
|
|
|
|
|
|
|
|
class GameSourceService {
|
|
|
|
|
|
|
|
|
|
const IS_FIXED_IOS13 = true;
|
|
|
|
|
const DEBUG = true;
|
|
|
|
|
|
|
|
|
|
public function __construct()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 获取IPA中的.app后缀目录
|
|
|
|
|
*/
|
|
|
|
|
public function getIpaAppPath($zip)
|
|
|
|
|
{
|
|
|
|
|
$appPath = '';
|
|
|
|
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
|
|
|
$name = $zip->getNameIndex($i);
|
|
|
|
|
if (preg_match("/^Payload.*?\.app/", $name, $matches)) {
|
|
|
|
|
$appPath = $matches[0];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $appPath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function deleteOldChannelConfigFolder($zip, $txChannelFolder)
|
|
|
|
|
{
|
|
|
|
|
for ($i = 0; $i < $zip->numFiles; $i++) {
|
|
|
|
|
$name = $zip->getNameIndex($i);
|
|
|
|
|
if (strpos($name, $txChannelFolder) === 0) {
|
|
|
|
|
$zip->deleteName($name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getChannelConfigFile($zip, $sdkVersion)
|
|
|
|
|
{
|
|
|
|
|
$configUrl = '';
|
|
|
|
|
if ($sdkVersion == 1) {
|
|
|
|
|
$configUrl = "META-INF/mch.properties";
|
|
|
|
|
} else {
|
|
|
|
|
$appPath = $this->getIpaAppPath($zip);
|
|
|
|
|
$configUrl = $appPath . '/_CodeSignature/TXChannel';
|
|
|
|
|
}
|
|
|
|
|
return $configUrl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getChannelConfigFolder($zip, array $packData)
|
|
|
|
|
{
|
|
|
|
|
$appPath = $this->getIpaAppPath($zip);
|
|
|
|
|
return $appPath . '/TXChannel/' . Base62::encode(json_encode($packData, JSON_UNESCAPED_UNICODE));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getGameSourceUrl($gameSource)
|
|
|
|
|
{
|
|
|
|
|
if (empty($gameSource)) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
$path = '';
|
|
|
|
|
if($gameSource['file_type'] == 1) {
|
|
|
|
|
$path = './Uploads/SourcePack/';
|
|
|
|
|
}else{
|
|
|
|
|
$path = './Uploads/Ios/original/';
|
|
|
|
|
}
|
|
|
|
|
$fileUrl = $path . $gameSource['file_name'];
|
|
|
|
|
return ROOTTT . ltrim($fileUrl, './');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function packChannel($localPath, $game, $gameSource, $apply = null)
|
|
|
|
|
{
|
|
|
|
|
$packData = [
|
|
|
|
|
'game_id' => $game['id'],
|
|
|
|
|
'game_name' => $game['game_name'],
|
|
|
|
|
'game_appid' => $game['game_appid'],
|
|
|
|
|
'promote_id' => $apply ? $apply['promote_id'] : '0',
|
|
|
|
|
'promote_account' => $apply ? $apply['promote_account'] : '自然渠道',
|
|
|
|
|
'source_version' => $gameSource['source_version'],
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$zip = new \ZipArchive();
|
|
|
|
|
if (!$zip->open($localPath, \ZipArchive::CREATE)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self::IS_FIXED_IOS13 && $game['sdk_version'] == 2) {
|
|
|
|
|
$channelFolder = $this->getChannelConfigFolder($zip, $packData);
|
|
|
|
|
return $this->packChannelFolder($zip, $channelFolder);
|
|
|
|
|
} else {
|
|
|
|
|
$channelFile = $this->getChannelConfigFile($zip, $game['sdk_version']);
|
|
|
|
|
return $this->packChannelFile($zip, $channelFile, $packData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$zip->close();
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 打入渠道信息文件
|
|
|
|
|
* @param string $zip 包文件
|
|
|
|
|
* @param string $distFile 打入文件名
|
|
|
|
|
* @param array $packData 打入信息
|
|
|
|
|
* @return boolean 是否成功
|
|
|
|
|
*/
|
|
|
|
|
public function packChannelFile($zip, $distFile, array $packData)
|
|
|
|
|
{
|
|
|
|
|
$zip->addFromString($distFile, json_encode($packData));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 打入渠道信息目录(用于IOS,主要为了解决IOS13问题)
|
|
|
|
|
* @param string $zip 包文件
|
|
|
|
|
* @param string $distFolder 打入文件夹
|
|
|
|
|
* @return boolean 是否成功
|
|
|
|
|
*/
|
|
|
|
|
public function packChannelFolder($zip, $distFolder)
|
|
|
|
|
{
|
|
|
|
|
$rows = explode('/' , $distFolder);
|
|
|
|
|
unset($rows[count($rows) -1]);
|
|
|
|
|
$txChannelFolder = implode('/', $rows) . '/';
|
|
|
|
|
$this->deleteOldChannelConfigFolder($zip, $txChannelFolder);
|
|
|
|
|
$zip->addEmptyDir($distFolder);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 原包打包
|
|
|
|
|
*/
|
|
|
|
|
public function sourcePack($gameSource, $game)
|
|
|
|
|
{
|
|
|
|
|
$relativeUrl = $gameSource['file_url'];
|
|
|
|
|
$localPath = ROOTTT . ltrim($relativeUrl, './');
|
|
|
|
|
|
|
|
|
|
$originalUrl = '';
|
|
|
|
|
if ($game['sdk_version'] == 2) {
|
|
|
|
|
$oldLocalPath = $localPath;
|
|
|
|
|
$localPath = str_replace('Uploads/SourcePack', 'Uploads/Ios/original', $oldLocalPath);
|
|
|
|
|
$originalUrl = $relativeUrl;
|
|
|
|
|
$relativeUrl = str_replace('Uploads/SourcePack', 'Uploads/Ios/original', $relativeUrl);
|
|
|
|
|
copy($oldLocalPath, $localPath);
|
|
|
|
|
}
|
|
|
|
|
$status = $this->packChannel($localPath, $game, $gameSource);
|
|
|
|
|
if (!$status) {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,原包加入信息失败!',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$distFilePath = 'SourcePack/' . $gameSource['file_name'];
|
|
|
|
|
$result = $this->uploadPackage($localPath, $distFilePath);
|
|
|
|
|
$fileUrl = '';
|
|
|
|
|
if ($result['status']) {
|
|
|
|
|
$fileUrl = $result['data']['url'];
|
|
|
|
|
$fileUrl = $fileUrl == '@' ? $relativeUrl : $fileUrl;
|
|
|
|
|
} else {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,上传OSS失败!' . $result['message'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$plistUrl = '';
|
|
|
|
|
$orgPlistUrl = '';
|
|
|
|
|
if ($game['sdk_version'] == 2) {
|
|
|
|
|
$params = [
|
|
|
|
|
'packageName' => $gameSource['bao_name'],
|
|
|
|
|
'gameId' => $game['id'],
|
|
|
|
|
'gameName' => $game['game_name'],
|
|
|
|
|
'promoteId' => 0,
|
|
|
|
|
'packageUrl' => $fileUrl,
|
|
|
|
|
'gameIcon' => get_cover($game['icon'], 'path'),
|
|
|
|
|
'type' => 'pack'
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
$result = $this->createPlist($params);
|
|
|
|
|
if ($result['status']) {
|
|
|
|
|
$plistUrl = $result['data']['path'];
|
|
|
|
|
} else {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,生成plist文件失败!' . $result['message'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$params['type'] = 'org';
|
|
|
|
|
$result = $this->createPlist($params);
|
|
|
|
|
if ($result['status']) {
|
|
|
|
|
$orgPlistUrl = $result['data']['path'];
|
|
|
|
|
} else {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,生成原包plist文件失败!' . $result['message'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return [
|
|
|
|
|
'status' => true,
|
|
|
|
|
'message' => '打包成功!',
|
|
|
|
|
'data' => [
|
|
|
|
|
'plistUrl' => $plistUrl,
|
|
|
|
|
'orgPlistUrl' => $orgPlistUrl,
|
|
|
|
|
'fileUrl' => $fileUrl,
|
|
|
|
|
'originalUrl' => $originalUrl,
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 渠道打包
|
|
|
|
|
*/
|
|
|
|
|
public function channelPack($gameSource, $game, $apply, $launchCount = 0)
|
|
|
|
|
{
|
|
|
|
|
$debugTime1 = microtime(true);
|
|
|
|
|
|
|
|
|
|
$gameSourceUrl = $this->getGameSourceUrl($gameSource);
|
|
|
|
|
if ($gameSource == null || !file_exists($gameSourceUrl)) {
|
|
|
|
|
M('apply', 'tab_')->where(['id' => $apply['id']])->setField('enable_status', -1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 检测是否存在投放申请,存在则更改投放申请信息,否则进行渠道打包 */
|
|
|
|
|
if ($launchCount > 0) {
|
|
|
|
|
M('apply', 'tab_')->where(['id' => $apply['id']])->setField('enable_status', 3);
|
|
|
|
|
$launchData = ['launch_packge' => 2, 'launch_down_url'=>'' , 'launch_plist_url'=>''];
|
|
|
|
|
M('apply_launch', 'tab_')->where(['apply_id' => $apply['id'], 'launch_packge'=>['in', [0, 2, 3]]])->save($launchData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$savePath = '';
|
|
|
|
|
$fileName = 'game_package' . $apply['game_id'] . '-' . $apply['promote_id'];
|
|
|
|
|
if ($apply['sdk_version'] == 1) {
|
|
|
|
|
$fileName .= '.apk';
|
|
|
|
|
$savePath = 'Uploads/GamePack/' . $fileName;
|
|
|
|
|
} else {
|
|
|
|
|
$fileName .= '.ipa';
|
|
|
|
|
$savePath = 'Uploads/IosGamePack/' . $fileName;
|
|
|
|
|
}
|
|
|
|
|
$relativePath = './' . $savePath;
|
|
|
|
|
$localPath = ROOTTT . $savePath;
|
|
|
|
|
|
|
|
|
|
$debugTime2 = microtime(true);
|
|
|
|
|
|
|
|
|
|
copy($gameSourceUrl, $localPath);
|
|
|
|
|
|
|
|
|
|
$debugTime3 = microtime(true);
|
|
|
|
|
|
|
|
|
|
$status = $this->packChannel($localPath, $game, $gameSource, $apply);
|
|
|
|
|
if (!$status) {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,加入渠道信息失败!',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$debugTime4 = microtime(true);
|
|
|
|
|
|
|
|
|
|
$distFilePath = 'GamePack/' . $fileName;
|
|
|
|
|
$result = $this->uploadPackage($localPath, $distFilePath, true);
|
|
|
|
|
if ($result['status']) {
|
|
|
|
|
$packageUrl = $result['data']['url'];
|
|
|
|
|
$packageUrl = $packageUrl == '@' ? $relativePath : $packageUrl;
|
|
|
|
|
} else {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,上传OSS失败!' . $result['message'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$debugTime5 = microtime(true);
|
|
|
|
|
|
|
|
|
|
$plistInfo = ['game_id' => $apply['game_id'], 'promote_id' => $apply['promote_id']];
|
|
|
|
|
$plistUrl = '';
|
|
|
|
|
if ($apply['sdk_version'] == 2) {
|
|
|
|
|
$params = [
|
|
|
|
|
'packageName' => $gameSource['bao_name'],
|
|
|
|
|
'gameId' => $game['id'],
|
|
|
|
|
'gameName' => $game['game_name'],
|
|
|
|
|
'promoteId' => $apply['promote_id'],
|
|
|
|
|
'packageUrl' => $packageUrl,
|
|
|
|
|
'gameIcon' => get_cover($game['icon'], 'path'),
|
|
|
|
|
'type' => 'pack'
|
|
|
|
|
];
|
|
|
|
|
$result = $this->createPlist($params);
|
|
|
|
|
if ($result['status']) {
|
|
|
|
|
$plistUrl = $result['data']['path'];
|
|
|
|
|
} else {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '打包失败,生成plist文件失败!' . $result['message'],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
$applyService = new ApplyService();
|
|
|
|
|
$applyService->updateAfterPack($apply, $packageUrl, $plistUrl);
|
|
|
|
|
|
|
|
|
|
$debugTime6 = microtime(true);
|
|
|
|
|
$debugInfo = '';
|
|
|
|
|
if (self::DEBUG) {
|
|
|
|
|
$debugInfo .= '[' .
|
|
|
|
|
'总计:' . ($debugTime6 - $debugTime1) .
|
|
|
|
|
' 复制:' . ($debugTime3 - $debugTime2) .
|
|
|
|
|
' 打包:' . ($debugTime4 - $debugTime3) .
|
|
|
|
|
' 上传:' . ($debugTime5 - $debugTime4) .
|
|
|
|
|
']';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [
|
|
|
|
|
'status' => true,
|
|
|
|
|
'message' => '打包成功!' . $debugInfo,
|
|
|
|
|
'data' => [
|
|
|
|
|
'plistUrl' => $plistUrl,
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function uploadPackage($localFilePath, $distFilePath, $isDeleteLocal = false)
|
|
|
|
|
{
|
|
|
|
|
$isChunk = C('PACKAGE_CHUNK_ENABLED') ? true : false;
|
|
|
|
|
if (get_tool_status('oss_storage') == 1) {
|
|
|
|
|
if ($isChunk) {
|
|
|
|
|
return $this->uploadPackageChunk($localFilePath, $distFilePath, $isDeleteLocal);
|
|
|
|
|
} else {
|
|
|
|
|
return $this->uploadPackageOnce($localFilePath, $distFilePath, $isDeleteLocal);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// 不上传OSS等第三方服务器
|
|
|
|
|
return [
|
|
|
|
|
'status' => true,
|
|
|
|
|
'message' => '上传成功',
|
|
|
|
|
'data' => [
|
|
|
|
|
'url' => '@'
|
|
|
|
|
],
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
public function uploadPackageChunk($localFilePath, $distFilePath, $isDeleteLocal = false)
|
|
|
|
|
{
|
|
|
|
|
$client = new Client([
|
|
|
|
|
'base_uri' => C('PACKAGE_CHUNK_URL'),
|
|
|
|
|
'timeout' => 10.0,
|
|
|
|
|
]);
|
|
|
|
|
$response = $client->post('/upload', [
|
|
|
|
|
'verify' => false,
|
|
|
|
|
'form_params' => [
|
|
|
|
|
'file' => $localFilePath,
|
|
|
|
|
'dest' => $distFilePath,
|
|
|
|
|
'is_delete_local' => ($isDeleteLocal ? 1 : 0),
|
|
|
|
|
]
|
|
|
|
|
]);
|
|
|
|
|
$result = (string)$response->getBody();
|
|
|
|
|
$result = json_decode($result, true);
|
|
|
|
|
if (!$result) {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '请求打包失败',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function uploadPackageOnce($localFilePath, $distFilePath, $isDeleteLocal = false)
|
|
|
|
|
{
|
|
|
|
|
$ossService = new OssService();
|
|
|
|
|
$result = $ossService->upload($localFilePath, $distFilePath);
|
|
|
|
|
if ($isDeleteLocal && file_exists($localFilePath)) {
|
|
|
|
|
@unlink($localFilePath);
|
|
|
|
|
}
|
|
|
|
|
return $result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//生成游戏渠道plist文件
|
|
|
|
|
public function createPlist($params)
|
|
|
|
|
{
|
|
|
|
|
$packageName = $params['packageName'] ?? '';
|
|
|
|
|
$gameName = $params['gameName'] ?? '';
|
|
|
|
|
$gameId = $params['gameId'] ?? 0;
|
|
|
|
|
$promoteId = $params['promoteId'] ?? 0;
|
|
|
|
|
$packageUrl = $params['packageUrl'] ?? '';
|
|
|
|
|
$platformId = $params['platformId'] ?? 0;
|
|
|
|
|
$position = $params['position'] ?? 0;
|
|
|
|
|
$gameIcon = $params['gameIcon'] ?? '';
|
|
|
|
|
$type = $params['type'] ?? '';
|
|
|
|
|
|
|
|
|
|
if ($gameId == 0) {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '游戏ID错误',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
if ($type == '' || !in_array($type, ['org', 'pack'])) {
|
|
|
|
|
return [
|
|
|
|
|
'status' => false,
|
|
|
|
|
'message' => '类型错误',
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$xml = new \DOMDocument();
|
|
|
|
|
$xml->loadXML(PlistDemo::$content);
|
|
|
|
|
$online = $xml->getElementsByTagName('dict'); //查找节点
|
|
|
|
|
$elements = $online->item(1)->getElementsByTagName('string'); //第二个节点下所有string
|
|
|
|
|
foreach ($elements as $element) {
|
|
|
|
|
switch ($element->textContent) {
|
|
|
|
|
case 'ipa_url':
|
|
|
|
|
if (preg_match("/http/", $packageUrl)) {
|
|
|
|
|
$element->nodeValue = $packageUrl;
|
|
|
|
|
} else {
|
|
|
|
|
$element->nodeValue = C('DOMAIN_DOWNLOAD') . ltrim($packageUrl, '.');
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'icon':
|
|
|
|
|
if (preg_match("/http/", $gameIcon)) {
|
|
|
|
|
$element->nodeValue = $gameIcon;
|
|
|
|
|
} else {
|
|
|
|
|
$element->nodeValue = C('DOMAIN_OFFICIAL_PC') . ltrim($gameIcon, '.');
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'com.dell':
|
|
|
|
|
$element->nodeValue = $packageName;
|
|
|
|
|
break;
|
|
|
|
|
case '1.0.0':
|
|
|
|
|
$element->nodeValue = false;
|
|
|
|
|
break;
|
|
|
|
|
case 'mchdemo':
|
|
|
|
|
$element->nodeValue = $gameName;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$fileName = '';
|
|
|
|
|
if ($type == 'pack') {
|
|
|
|
|
if ($promoteId == 0) {
|
|
|
|
|
$fileName = 'Uploads/SourcePlist/'. $gameId . '.Plist';
|
|
|
|
|
} elseif ($platformId > 0) {
|
|
|
|
|
$fileName = 'Uploads/GamePlist/'. $gameId . '-' . $promoteId . '-' . $platformId . '-' .$position . '.Plist';
|
|
|
|
|
} else {
|
|
|
|
|
$fileName = 'Uploads/GamePlist/'. $gameId . '-' . $promoteId . '.Plist';
|
|
|
|
|
}
|
|
|
|
|
} elseif ($type == 'org') {
|
|
|
|
|
$fileName = 'Uploads/OrgSourcePlist/'. $gameId . '.Plist';
|
|
|
|
|
}
|
|
|
|
|
$xml->save('./' . $fileName);
|
|
|
|
|
return [
|
|
|
|
|
'status' => true,
|
|
|
|
|
'message' => '生成成功',
|
|
|
|
|
'data' => [
|
|
|
|
|
'path' => './' . $fileName
|
|
|
|
|
]
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
}
|