Unity Xcode 导出工程的配置
使用PBXProject可以设置很多xcode的配置选项
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System.IO;
#if UNITY_IOS && UNITY_EDITOR
using UnityEditor.iOS.Xcode;
using UnityEditor.iOS.Xcode.Extensions;
class BuildPostProcessor
{
// ios版本xcode工程维护代码
[PostProcessBuild]
public static void OnPostprocessBuild(BuildTarget BuildTarget, string path)
{
if (BuildTarget == BuildTarget.iOS)
{
string projPath = PBXProject.GetPBXProjectPath(path);
PBXProject proj = new PBXProject();
proj.ReadFromString(File.ReadAllText(projPath));
// 获取当前项目名字
string target = proj.TargetGuidByName(PBXProject.GetUnityTargetName());
// 对所有的编译配置设置选项
proj.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
proj.SetBuildProperty(target, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
proj.AddBuildProperty(target, "OTHER_LDFLAGS", "-ObjC");
// 添加依赖库
proj.AddFrameworkToProject (target, "AdSupport.framework", false);
proj.AddFrameworkToProject (target, "CoreTelephony.framework", false);
proj.AddFrameworkToProject (target, "QuartzCore.framework", false);
proj.AddFrameworkToProject (target, "Security.framework", false);
proj.AddFrameworkToProject (target, "StoreKit.framework", false);
proj.AddFrameworkToProject (target, "SystemConfiguration.framework", false);
proj.AddFrameworkToProject (target, "libc++.tbd", false);
proj.AddFrameworkToProject (target, "libz.tbd", false);
proj.AddFrameworkToProject (target, "libsqlite3.0.tbd", false);
proj.AddFrameworkToProject (target, "libsqlite3.tbd", false);
proj.AddFrameworkToProject (target, "CoreFoundation.framework", false);
proj.AddFrameworkToProject (target, "CFNetwork.framework", false);
proj.AddFrameworkToProject (target, "CoreGraphics.framework", false);
proj.AddFrameworkToProject (target, "Foundation.framework", false);
proj.AddFrameworkToProject (target, "UIKit.framework", false);
proj.AddFrameworkToProject (target, "libresolv.tbd", false);
proj.AddFrameworkToProject (target, "UserNotifications.framework", false);
// 设置签名
//proj.SetBuildProperty (target, "CODE_SIGN_IDENTITY", "iPhone Distribution: _______________");
//proj.SetBuildProperty (target, "PROVISIONING_PROFILE", "********-****-****-****-************");
const string defaultLocationInProj = "Plugins/iOS";
const string coreFrameworkName = "xxx_sdk.framework";
string framework = Path.Combine(defaultLocationInProj, coreFrameworkName);
string fileGuid = proj.AddFile(framework, "Frameworks/" + framework, PBXSourceTree.Sdk);
PBXProjectExtensions.AddFileToEmbedFrameworks(proj, target, fileGuid);
// 保存工程
proj.WriteToFile (projPath);
// 修改plist
string plistPath = path + "/Info.plist";
PlistDocument plist = new PlistDocument();
plist.ReadFromString(File.ReadAllText(plistPath));
PlistElementDict rootDict = plist.root;
// 语音所需要的声明,iOS10必须
rootDict.SetString("NSPhotoLibraryUsageDescription", "是否允许此游戏使用系统相册?");
rootDict.SetString("NSPhotoLibraryAddUsageDescription", "是否允许此游戏使用系统相册附加功能?");
rootDict.SetString("NSCameraUsageDescription", "允许访问相机");
//微信白名单
PlistElementArray array = rootDict.CreateArray("LSApplicationQueriesSchemes");
array.AddString("weixin");
//微信分享回调
PlistElementArray urlArray = rootDict.CreateArray("CFBundleURLTypes");
PlistElementDict dic = urlArray.AddDict();
dic.SetString("CFBundleTypeRole", "Editor");
dic.SetString("CFBundleURLName", "weixin");
PlistElementArray dicArray = dic.CreateArray("CFBundleURLSchemes");
dicArray.AddString("xxxxxxkeyxxxxxxx");
PlistElementDict dictTmp = rootDict.CreateDict("NSAppTransportSecurity");
dictTmp.SetBoolean( "NSAllowsArbitraryLoads", true);
// 保存plist
plist.WriteToFile (plistPath);
}
}
}
#endif
添加sdk库文件
新建一个入口类 CustomAppController.mm
交互类 MySDK.h
MySDK.mm
。
全往这个工程目录 plugins/IOS/
里扔。这个下面所有的代码和库资源会在打包时放入xcode工程的Libraries下面
Unity 添加自定义的入口和调用类
unity生成的xcode工程默认入口为 UnityAppController
。可以用自定义入口 CustomAppController.mm
替代这个类,并实现sdk需要添加的生命周期回调。
关键代码为调用 IMPL_APP_CONTROLLER_SUBCLASS(CustomAppController)
。
这个宏的定义是这样的
#define IMPL_APP_CONTROLLER_SUBCLASS(ClassName)
@interface ClassName(OverrideAppDelegate)
{
}
+(void)load;
@end
@implementation ClassName(OverrideAppDelegate)
+(void)load
{
extern const char* AppControllerClassName;
AppControllerClassName = #ClassName;
}
@end
这里的代码使用了object-c的一些特性,其中扩展load这个函数的意思就是,在这个类被加载到内存时执行这个事情,它会自动把main里面的 AppControllerClassName改成你的。然后往生命周期函数的回调里添加sdk要求的函数。
完整代码
#import "UnityAppController.h"
@interface CustomAppController : UnityAppController {}
@end
IMPL_APP_CONTROLLER_SUBCLASS (CustomAppController)
@implementation CustomAppController
// - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// // self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// // self.window.backgroundColor = [UIColor whiteColor];
// // self.window.rootViewController = [[ViewController alloc] init];
// // [self.window makeKeyAndVisible];
// return YES;
// }
// - (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
// }
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{
return YES;
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
}
// - (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
// }
// - (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// }
//关于屏幕旋转问题 在AppDelegate中加入该函数
//- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window {
// //横屏游戏:UIInterfaceOrientationMaskLandscape 竖屏游戏:UIInterfaceOrientationMaskPortrait
// return UIInterfaceOrientationMaskLandscape;
//}
@end
Unity 和 Ios 交互
Ios的部分:
MySDK.h
#import <xxx_sdk/xxx_sdk.h>
// Controller to support native rendering callback
@interface DMSDK : NSObject<
PlatformDelegate,
PlatformPayDelegate>
@end
MySDK.mm
#import "DMSDK.h"
@implementation DMSDK
NSString * const UNITY_SDK_OBJ = @"SdkObj";
- (void)SDKInit
{
[[GHomeAPI sharedGHome] initialize:self appId:@"xxxxxxx11"];
}
#pragma mark - GHomeAPIInitializeDelegate
- (void)initializeResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg{
// NSString * string = [NSString stringWithFormat:@"resultCode:%ld,resultMsg:%@",(long)resultCode,resultMsg];
// [self appendLogInfo:string];
// if (resultCode == 0) {
// self.loginBtn.enabled = true;
// }
}
- (void)SDKLogin
{
[[GHomeAPI sharedGHome] login:self];
}
#pragma mark - GHomeAPILoginDelegate
- (void)loginResult:(NSInteger)resultCode resultMsg:(NSString *)resultMsg ticket:(NSString *)ticket userId:(NSString *)userId
{
NSString* string = @"";
// GHOMEAPI_CONSTANTS_SUCCESS
// GHOMEAPI_CONSTANTS_CANCEL_LOGIN
if (0 == resultCode)
{
string = [NSString stringWithFormat:@"{\"code\":1,\"userid\":\"%@\",\"ticket\":\"%@\",\"callbackType\":\"Login\"}",
userId, ticket];
UnitySendMessage([UNITY_SDK_OBJ UTF8String], "OnGameSdkCallback", [string UTF8String]);
}
else
{
string = @"{\"code\":0,\"callbackType\":\"Login\"}";
UnitySendMessage([UNITY_SDK_OBJ UTF8String], "OnGameSdkCallback", [string UTF8String]);
}
}
- (void)SDKLogout
{
[[GHomeAPI sharedGHome] logout:self];
}
- (void)logoutResult:(NSInteger)resultCode resultMsg:(NSString*)resultMsg
{
// showAlertView(@"logoutResult code[%@] msg[%@]", @(resultCode), resultMsg);
NSString* string = @"";
if (0 == resultCode)
{
string = @"{\"code\":1,\"callbackType\":\"LoginOut\"}";
UnitySendMessage([UNITY_SDK_OBJ UTF8String], "OnGameSdkCallback", [string UTF8String]);
}
else
{
string = @"{\"code\":0,\"callbackType\":\"LoginOut\"}";
UnitySendMessage([UNITY_SDK_OBJ UTF8String], "OnGameSdkCallback", [string UTF8String]);
}
}
// 字典转json格式字符串:
+ (NSString*)dictionaryToJson:(NSDictionary *)dic
{
NSError *parseError = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dic options:NSJSONWritingPrettyPrinted error:&parseError];
return [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}
/*!
* @brief 把格式化的JSON格式的字符串转换成字典
* @param jsonString JSON格式的字符串
* @return 返回字典
*/
+ (NSDictionary *)dictionaryWithJsonString:(NSString *)jsonString {
if (jsonString == nil) {
return nil;
}
NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&err];
if(err) {
NSLog(@"json解析失败:%@",err);
return nil;
}
return dic;
}
- (void)DoExtend:(NSString*)jsonString
{
NSDictionary *parameter = [DMSDK dictionaryWithJsonString:jsonString];
[[GHomeAPI sharedGHome] extendFunction:nil type: GHOME_REPORT_ROLE_INFO_TYPE parameter:parameter];
}
- (void)CopyTextToClipboard:(NSString*)str
{
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = str;
}
- (void)SaveToAlbum:(NSString*)base64Img fileName:(NSString*)name
{
NSData* data=[NSData alloc];
data = [data initWithBase64EncodedString:base64Img options:(NSDataBase64DecodingIgnoreUnknownCharacters)];
UIImage* img=[UIImage imageWithData:data];
UIImageWriteToSavedPhotosAlbum(img, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
- (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo
{
if (error != NULL)
{
//[self Log:[error localizedDescription]];
}
else
{
//[self Log:@"succeed"];
}
}
- (void)ShowFloatIcon:(bool)isShow
{
}
- (NSString*)GetDeviceId
{
return [[GHomeAPI sharedGHome] deviceId];
}
@end
// NSString 转 CString
char* MakeStringCopy(const char* string)
{
if (string == NULL)
return NULL;
char* res = (char*)malloc(strlen(string) + 1);
strcpy(res, string);
return res;
}
#if defined(__cplusplus)
extern "C"{
#endif
static MySDK *mySDK;
void _PlatformInit()
{
if(mySDK == NULL)
{
mySDK = [[MySDK alloc]init];
}
[mySDK SDKInit];
}
void _PlatformLogin()
{
[mySDK SDKLogin];
}
void _PlatformLogout()
{
[mySDK SDKLogout];
}
void _PlatformDoExtend(const char *json)
{
NSString *str1 = [NSString stringWithCString:json encoding:NSUTF8StringEncoding];
[mySDK DoExtend:str1];
}
void _CopyTextToClipboard(const char *str)
{
NSString *str1 = [NSString stringWithCString:str encoding:NSUTF8StringEncoding];
[mySDK CopyTextToClipboard:str1];
}
void _SaveToAlbum(const char *base64Img, const char *name)
{
NSString *str1 = [NSString stringWithCString:base64Img encoding:NSUTF8StringEncoding];
NSString *str2 = [NSString stringWithCString:name encoding:NSUTF8StringEncoding];
[mySDK SaveToAlbum:str1 fileName:str2];
}
void _ShowFloatIcon(bool isShow)
{
[mySDK ShowFloatIcon:isShow];
}
const char* _GetDeviceId()
{
NSString *str = [mySDK GetDeviceId];
return MakeStringCopy([str UTF8String]);
}
#if defined(__cplusplus)
}
#endif
这里注意 NSString * const UNITY_SDK_OBJ = @"SdkObj";
SdkObj
为绑定交互类的 gameObject
然后是Unity的部分:
using System.Collections;
using System.IO;
using UnityEngine;
using LuaInterface;
using System;
using Oz.Framework;
using System.Collections.Generic;
using Oz.Framework.Utility;
using System.Runtime.InteropServices;
public class OzSDKManager : MonoBehaviour
{
public static OzSDKManager Instance { get; set; }
public OzExtendData extendData = null;
[NoToLua]
private void Awake()
{
if(Instance == null)
{
Instance = this;
}
}
[NoToLua]
void Start () {
extendData = new OzExtendData();
}
#if !UNITY_EDITOR && UNITY_IPHONE
[DllImport ("__Internal")]
private static extern void _PlatformInit();
[DllImport ("__Internal")]
private static extern void _PlatformLogin();
[DllImport ("__Internal")]
private static extern void _PlatformLogout();
[DllImport ("__Internal")]
private static extern void _PlatformDoExtend(string json);
[DllImport ("__Internal")]
private static extern void _CopyTextToClipboard(string str);
[DllImport ("__Internal")]
private static extern void _SaveToAlbum(string base64Img, string fileName);
[DllImport ("__Internal")]
private static extern void _ShowFloatIcon(bool isShow);
[DllImport ("__Internal")]
[DllImport ("__Internal")]
private static extern string _GetDeviceId();
#elif !UNITY_EDITOR && UNITY_ANDROID
// private AndroidJavaClass ajc_UnityPlayer = null;
// private AndroidJavaObject currentActivity = null;
private static AndroidJavaClass ajc_SDKCall = null;
private static void _PlatformInit()
{
ajc_SDKCall = new AndroidJavaClass("com.uainter.main.UAMain");
string json = "{'channel':'0','debugmode':0,'appid':'xxxx','appkey':'xxx','islandscape':false}";
ajc_SDKCall.CallStatic("uaInit",json);
}
private static void _PlatformLogin()
{
string json = "{}";
ajc_SDKCall.CallStatic("uaLogin",json);
}
private static void _PlatformLogout()
{
string json = "{}";
ajc_SDKCall.CallStatic("uaLogout",json);
}
private static void _PlatformDoExtend(string json)
{
ajc_SDKCall.CallStatic("uaDoExtend",json);
}
private static void _CopyTextToClipboard(string str)
{
ajc_SDKCall.CallStatic("copyTextToClipboard", str);
}
private static void _SaveToAlbum(string base64Img, string fileName)
{
ajc_SDKCall.CallStatic("SaveToAlbum", base64Img, fileName, "Lapis");
}
private static void _ShowFloatIcon(bool isShow)
{
string json = "{'isShow':'"+isShow+"'}";
ajc_SDKCall.CallStatic("uaShowFloatIcon",json);
}
private static string _GetDeviceId()
{
return ajc_SDKCall.CallStatic<string>("GetDeviceId");
}
#else
private static void _PlatformInit(){}
private static void _PlatformLogin(){}
private static void _PlatformLogout(){}
private static void _PlatformDoExtend(string json){}
private static void _CopyTextToClipboard(string str){}
private static void _SaveToAlbum(string base64Img, string fileName){}
private static void _ShowFloatIcon(bool isShow){}
private static string _GetDeviceId(){return "";}
#endif
[NoToLua]
private Action<String> actionResult;
public void Init()
{
//建议在Debug版本中调用此接口打开日志功能,Release版本中注释掉;
#if CONSOLE_ENABLE
GCrashReportInterface.ConfigDebugMode(true);
#endif
//初始化Crash Handler;
GCrashReportInterface.InitCrashHandler();
//Debug版本建议调用此接口显示设置为不加密;
#if CONSOLE_ENABLE
GCrashReportInterface.EnableEncryptLog(false);
#endif
//
_PlatformInit();
}
public void LoginSDK(Action<String> _action)
{
actionResult = _action;
_PlatformLogin();
}
public void LoginOutSDK(Action<String> _action)
{
actionResult = _action;
_PlatformLogout();
}
public void DoExtend(int _type, int _sType)
{
string json = "";
if (_type == 1) {
if (_sType == 1) {
extendData.submitType = "createRole";
}else if (_sType == 2) {
extendData.submitType = "selectServer";
}else if (_sType == 3) {
extendData.submitType = "enterServer";
}else if (_sType == 4) {
extendData.submitType = "levelUp";
}else if (_sType == 5) {
extendData.submitType = "exitServer";
}
json = JsonUtility.ToJson(extendData);
LogUtil.Log(json);
} else {
json = "{'commondId':'"+_type+"'}";
}
_PlatformDoExtend(json);
}
public void CopyTextToClipboard(string str)
{
_CopyTextToClipboard(str);
}
public void SaveToAlbum(Texture2D texture2D, string fileName)
{
byte[] bytes = texture2D.EncodeToJPG();
string base64Img = Convert.ToBase64String(bytes);
// DebugConsole.Log(base64Img.Length);
_SaveToAlbum(base64Img, fileName);
}
// -- SDK CallBack --
[NoToLua]
void OnGameSdkCallback(string str)
{
print ("OnGameSdkCallback str is " + str);
// stringToEdit = str;
if (null != actionResult)
{
actionResult(str);
actionResult = null;
}
}
public void ShowFloatIcon(bool isShow)
{
_ShowFloatIcon(isShow);
}
public string GetDeviceId()
{
return _GetDeviceId();
}
[NoToLua]
void OnApplicationPause(bool isPause)
{
if (isPause) {
_OnApplicationPause();
DoExtend(2, 1);
}
}
[NoToLua]
void OnApplicationFocus(bool isFocus)
{
if (isFocus)
{
_OnApplicationFocus();
}
}
[NoToLua]
void OnApplicationQuit()
{
_OnApplicationQuit();
}
}