前不久接完MSDK,又花了幾天時間改之前的打包工具和MSDK的一些代碼,主要是這邊有騷操作,需要不帶SDK的包和帶SDK的包,還有很多雜七雜八的包。然後順帶着打了個iOS測試包,檢測SDK有沒有接好。大廠給的插件中有對XCode工程進行配置,不需要手動去拖frameworks和添加代碼啥的,簡單方便。稍微改下,就能快速打iOS包。確認沒問題後,就馬不停蹄的開始接入米大師充值SDK。
米大師SDK也有Unity版的插件,就直接用這個,安卓上的接入相對簡單。XCode這邊就有點麻煩了,因爲米大師也在OnPostProcessBuild這個回調方法裏進行了處理,就對代碼進行了合併,發現各種問題,然後一個個解決過來。主要是MSDK和米大師都對XUPorter進行了修改,雖然後面全部解決了,但如果再有個第3方SDK,也用到了XUPorter,也進行了魔改,後面的維護不要太大啊。想了想,決定用Unity自帶的API來,不用大廠的代碼來自動配置,而且項目中Unity版本比較高,是2017版本的,也不需要配置其他插件,簡單方便。
參考了一些大佬文章,用Unity的自帶API也挺累的,很多都靠試,然後打包驗證,花了一兩天的時間結束,測試也沒問題,也說下遇到的問題,google有搜到說建議用ProjectCapabilityManager這個類,用過發現不好用,不知道是不是XCode版本太高導致的,還是怎麼了。PBXProject.AddCapability能開啓InAppPurchase,但ProjectCapabilityManager就不能開啓,後面就沒有用上,這是官方的Bug嗎?
代碼:邏輯應該還算比較清晰,就懶得一一註釋了。也測試過,MSDK和米大師都沒有問題。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEditor.iOS.Xcode;
using System.IO;
using System;
public class ZPXCodePostProcess
{
#if UNITY_EDITOR
[PostProcessBuild(1000)]
public static void OnPostProcessBuild(BuildTarget target, string pathToBuiltProject)
{
if (target != BuildTarget.iOS) return;
string projPath = PBXProject.GetPBXProjectPath(pathToBuiltProject);
PBXProject project = new PBXProject();
project.ReadFromString(File.ReadAllText(projPath));
GenerateProjectFile(project, pathToBuiltProject);
string plistPath = pathToBuiltProject + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
GeneratePlistFile(plist.root, plistPath);
File.WriteAllText(projPath, project.WriteToString());
File.WriteAllText(plistPath, plist.WriteToString());
DeployIOS.EditorCode(pathToBuiltProject);
}
/// <summary>
/// 處理XCode工程
/// </summary>
/// <param name="project"></param>
/// <param name="pathToBuiltProject"></param>
private static void GenerateProjectFile(PBXProject project, string pathToBuiltProject)
{
string target = project.TargetGuidByName(PBXProject.GetUnityTargetName());
project.SetBuildProperty(target, "CODE_SIGN_IDENTITY", "********");
project.SetBuildProperty(target, "PROVISIONING_PROFILE_SPECIFIER", "******");
project.SetBuildProperty(target, "DEVELOPMENT_TEAM", "******");
project.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
project.SetBuildProperty(target, "CODE_SIGNING_STYLE", "MANUAL");
// 添加flag
project.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC");
// 添加系統庫
AddSystemFramework(project, target);
// 添加第3方
AddOther(project, target, pathToBuiltProject);
//project.AddCapability(target, PBXCapabilityType.PushNotifications);
project.AddCapability(target, PBXCapabilityType.InAppPurchase);
project.AddCapability(target, PBXCapabilityType.BackgroundModes);
}
private static void AddSystemFramework(PBXProject project, string target)
{
string[] frameworks =
{
"libz.dylib",
"libz.1.1.3.dylib",
"libsqlite3.dylib",
"libxml2.dylib",
"libc++.dylib",
"libstdc++.dylib",
"CoreTelephony.framework",
"SystemConfiguration.framework",
"UIKit.framework",
"Foundation.framework",
"CoreGraphics.framework",
"MobileCoreServices.framework",
"StoreKit.framework",
"CFNetwork.framework",
"CoreData.framework",
"Security.framework",
"CoreLocation.framework",
"ImageIO.framework",
"CoreText.framework",
"QuartzCore.framework",
"AdSupport.framework",
"Accelerate.framework",
"CoreImage.framework",
"SafariServices.framework",
"Social.framework",
"JavaScriptCore.framework",
"AssetsLibrary.framework",
"MediaPlayer.framework",
"AddressBook.framework",
"CoreMotion.framework",
"AVFoundation.framework",
"MessageUI.framework",
"EventKit.framework",
"EventKitUI.framework",
"CoreAudio.framework",
};
foreach (var framework in frameworks)
{
project.AddFrameworkToProject(target, framework, false);
}
}
private static void AddOther(PBXProject project, string target, string pathToBuiltProject)
{
UpdateiOSPlugin(pathToBuiltProject);
// 添加MSDK相關
project.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Third/MSDK");
AddFile(project, target, "Third/MSDK/MSDK.framework");
AddFile(project, target, "Third/MSDK/MSDKResources.bundle");
AddFile(project, target, "Third/MSDK/WGPlatformResources.bundle");
AddFile(project, target, "Third/MSDK/MSDKAdapter.framework");
// Bugly
project.AddBuildProperty(target, "LIBRARY_SEARCH_PATHS", "$(PROJECT_DIR)/Third/Bugly");
AddFile(project, target, "Third/Bugly/BuglyBridge.h");
AddFile(project, target, "Third/Bugly/libBuglyBridge.a");
// 添加米大師相關
project.AddBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", "$(PROJECT_DIR)/Third/Midas/local");
AddFile(project, target, "Third/Midas/local/MidasIAPSDK.bundle");
AddFile(project, target, "Third/Midas/local/MidasIAPSDK.framework");
AddFile(project, target, "Third/Midas/Script/MidasLocalIAPSDKAdapter.h");
AddFile(project, target, "Third/Midas/Script/MidasSdkConnector.h");
AddFile(project, target, "Third/Midas/Script/MidasLocalIAPSDKAdapter.m");
AddFile(project, target, "Third/Midas/Script/MidasSdkConnector.m");
}
private static bool UpdateiOSPlugin(string pathToBuiltProject)
{
bool bIsFinish = false;
try
{
int lastIndex = Application.dataPath.LastIndexOf("/");
string sdkPluginPath = Application.dataPath.Substring(0, lastIndex) + "/PlatformSDKPlugin/iOS/Third";
// C++11 版本
if(ConfigSettings.Instance.UseC11)
sdkPluginPath += "_C11";
if (Directory.Exists(sdkPluginPath))
{
int length = sdkPluginPath.Length;
if ('/' == sdkPluginPath[length - 1] || '\\' == sdkPluginPath[length - 1])
--length;
string[] files = Directory.GetFiles(sdkPluginPath, "*.*", SearchOption.AllDirectories);
for (int i = 0; i < files.Length; ++i)
{
string tempStr = files[i].Remove(0, length);
string tempDestPath = pathToBuiltProject + "/Third/" + tempStr;
string tempDir = Path.GetDirectoryName(tempDestPath);
if (!Directory.Exists(tempDir))
Directory.CreateDirectory(tempDir);
File.Copy(files[i], tempDestPath, true);
}
}
bIsFinish = true;
}
catch (Exception e)
{
Debug.LogException(e);
}
return bIsFinish;
}
private static void AddFile(PBXProject project, string target, string destPath)
{
project.AddFileToBuild(target, project.AddFile(destPath, destPath, PBXSourceTree.Source));
}
/// <summary>
/// 處理Plist工程
/// </summary>
/// <param name="project"></param>
/// <param name="plistPath"></param>
private static void GeneratePlistFile(PlistElementDict rootDict, string plistPath)
{
PlistElementArray urlArray = null;
if (!rootDict.values.ContainsKey("CFBundleURLTypes"))
urlArray = rootDict.CreateArray("CFBundleURLTypes");
else
urlArray = rootDict.values["CFBundleURLTypes"].AsArray();
var urlTypeDict = urlArray.AddDict();
urlTypeDict.SetString("CFBundleTypeRole", "Editor");
urlTypeDict.SetString("CFBundleURLName", "weixin");
var urlScheme = urlTypeDict.CreateArray("CFBundleURLSchemes");
urlScheme.AddString(DeploySettings.Instance.WxAppId);
urlTypeDict = urlArray.AddDict();
urlTypeDict.SetString("CFBundleTypeRole", "Editor");
urlTypeDict.SetString("CFBundleURLName", "tencentopenapi");
urlScheme = urlTypeDict.CreateArray("CFBundleURLSchemes");
urlScheme.AddString("tencent" + DeploySettings.Instance.QqAppId);
urlTypeDict = urlArray.AddDict();
urlTypeDict.SetString("CFBundleTypeRole", "Editor");
urlTypeDict.SetString("CFBundleURLName", "tencentvideo");
urlScheme = urlTypeDict.CreateArray("CFBundleURLSchemes");
urlScheme.AddString("tencentvideo" + DeploySettings.Instance.QqAppId);
urlTypeDict = urlArray.AddDict();
urlTypeDict.SetString("CFBundleTypeRole", "Editor");
urlTypeDict.SetString("CFBundleURLName", "QQ");
urlScheme = urlTypeDict.CreateArray("CFBundleURLSchemes");
urlScheme.AddString(DeploySettings.Instance.QqScheme);
urlTypeDict = urlArray.AddDict();
urlTypeDict.SetString("CFBundleTypeRole", "Editor");
urlTypeDict.SetString("CFBundleURLName", "QQLaunch");
urlScheme = urlTypeDict.CreateArray("CFBundleURLSchemes");
urlScheme.AddString("tencentlaunch" + DeploySettings.Instance.QqAppId);
rootDict.SetString("CHANNEL_DENGTA", "***");
rootDict.SetString("MSDK_OfferId", DeploySettings.Instance.IOSOfferId);
rootDict.SetString("MSDK_ENV", ConfigSettings.Instance.MsdkUrlEnv);
rootDict.SetString("QQAppID", DeploySettings.Instance.QqAppId);
rootDict.SetString("WXAppID", DeploySettings.Instance.WxAppId);
rootDict.SetString("MSDKKey", DeploySettings.Instance.MsdkKey);
rootDict.SetBoolean("MSDK_PUSH_SWITCH", true);
rootDict.SetBoolean("AutoRefreshToken", true);
rootDict.SetBoolean("NeedNotice", true);
rootDict.SetInteger("NoticeTime", 900);
rootDict.SetInteger("MSDK_REAL_NAME_AUTH_SWITCH", 1);
rootDict.SetBoolean("MSDK_Webview_Landscape_NavBar_Hideable", false);
rootDict.SetBoolean("MSDK_Webview_Portrait_NavBar_Hideable", false);
if (!rootDict.values.ContainsKey("LSApplicationQueriesSchemes"))
urlArray = rootDict.CreateArray("LSApplicationQueriesSchemes");
else
urlArray = rootDict.values["LSApplicationQueriesSchemes"].AsArray();
urlArray.AddString("mqq");
urlArray.AddString("mqqapi");
urlArray.AddString("wtloginmqq2");
urlArray.AddString("mqqopensdkapiV4");
urlArray.AddString("mqqopensdkapiV3");
urlArray.AddString("mqqopensdkapiV2");
urlArray.AddString("mqqwpa");
urlArray.AddString("mqqOpensdkSSoLogin");
urlArray.AddString("mqqgamebindinggroup");
urlArray.AddString("mqqopensdkfriend");
urlArray.AddString("mqzone");
urlArray.AddString("weixin");
urlArray.AddString("wechat");
rootDict.SetString("NSCameraUsageDescription", "");
rootDict.SetString("NSPhotoLibraryUsageDescription", "");
if (rootDict.values.ContainsKey("NSAppTransportSecurity"))
rootDict.values.Remove("NSAppTransportSecurity");
PlistElementDict urlDict = rootDict.CreateDict("NSAppTransportSecurity");
urlDict.SetBoolean("NSAllowsArbitraryLoads", true);
}
#endif
}
這邊需要記一下other linker flages參數中-all_load這個參數,坑了我一天,因爲米大師Demo中有這個參數,我也用上了,然後各種duplicate symbol錯誤,剛開始還以爲是安全SDK的問題,因爲接完安全SDK後就沒有打iOS工程,導致我把米大師和安全SDK全刪了,發現還有這個錯誤,對比了各種配置文件,才找到問題所在。
參考: