前不久接完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);
}
///
/// 处理XCode工程
///
///
///
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));
}
///
/// 处理Plist工程
///
///
///
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全删了,发现还有这个错误,对比了各种配置文件,才找到问题所在。
参考:
配置Xcode工程
PBXProject.AddFile Code Examples