在Object-C的工具里面吧***.mm写好,放到Unity项目的Assets/Plugins/iOS下面。(Unity2018及以上只要放在任意iOS的夹下即可)
在C#里面写上代static extern的 函数,与C里面的函数同名。
一.基础的调用参数,无传参
ocClass.mm
extern "C" {
//从C#调用
void CallOC() {
NSLog(@"Object-c Called.");
CsharpCallOC.cs
using System.Runtime.InteropServices;
public class CsharpCallOC {
//调用ocClass.mm里面的同名函数
[DllImport("__Internal")]
private static extern void CallOC();
二.传递参数
ocClass.mm
extern "C" {
//从C#调用
void CallOC(int val1, float val2, bool val3, const char *val4) {
NSLog(@"Object-c Called. val1=%d, val2=%f, val3=%d, val4=%s", val1, val2, val3, val4);
CsharpCallOC.cs
using System.Runtime.InteropServices;
public class CsharpCallOC {
//调用ocClass.mm里面的同名函数
[DllImport("__Internal")]
private static extern void CallOC(int val1, float val2, bool val3, string val4);
三.OC回调Unity
1.使用函数指针接口方法进行回调,可以传参,也可以带返回参数,调用灵活。(推荐使用)
2.UnitySendMessage()需要有固定的游戏物体,按名称查找,并且是激活状态,不能隐藏(不推荐,无法灵活使用)。
extern "C" {
// C#函数的函数指针
typedef void (*cs_callback)(int);
void CallOC(cs_callback callback) {
callback(999);
using System.Runtime.InteropServices;
using AOT;
public class CsharpCallOC {
delegate void callback_delegate(int val);
[DllImport("__Internal")]
private static extern void sampleMethod4(callback_delegate callback);
//回调函数,必须MonoPInvokeCallback并且是static
[MonoPInvokeCallback(typeof(callback_delegate))]
private static void cs_callback(int val) {
UnityEngine.Debug.Log ("cs_callback : " + val);
private static void sampleMethod4Invoker() {
//直接把函数传过去
sampleMethod4 (cs_callback);
此处记录unity编辑器打包xcode自动化脚本。大部分的目录与属性都可以个性成功。至于复制文件以Groud的方式,还有一些问题。需要处理多余引用资源的问题。工具可以后期考虑集成方式,做成成品工具。方便多元化出包。
using UnityEngine;
using UnityEditor;
using UnityEditor.Callbacks;
using System;
#if UNITY_EDITOR_OSX
using UnityEditor.iOS.Xcode;
#endif
using System.IO;
public class XcodeProjectMod : MonoBehaviour
#if UNITY_EDITOR_OSX
[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("Unity-iPhone");
string rootPath = projPath.Replace("Unity-iPhone.xcodeproj/project.pbxproj", "");
//复制sdk接口文件
var iosLibPath = "Sdk/IOSLib";
var classes = "Classes";
var fileName = "UnityAppController.mm";
var filePath = Path.Combine(iosLibPath, fileName);
var targetFilePath = Path.Combine(path, Path.Combine(classes, fileName));
File.Copy(filePath, targetFilePath, true);
fileName = "UnityAppController.h";
filePath = Path.Combine(iosLibPath, fileName);
targetFilePath = Path.Combine(path, Path.Combine(classes, fileName));
File.Copy(filePath, targetFilePath, true);
//创建swift桥接
fileName = "File.swift";
filePath = Path.Combine(iosLibPath, fileName);
targetFilePath = Path.Combine(path, fileName);
File.Copy(filePath, targetFilePath, true);
proj.AddFileToBuild(target, proj.AddFile(fileName, fileName, PBXSourceTree.Source));
fileName = "Unity-iPhone-Bridging-Header.h";
filePath = Path.Combine(iosLibPath, fileName);
targetFilePath = Path.Combine(path, fileName);
File.Copy(filePath, targetFilePath, true);
proj.AddFileToBuild(target, proj.AddFile(fileName, fileName, PBXSourceTree.Source));
//复制sdk文件到xcode目录下
var sdkPath = Application.dataPath.Replace("Assets", "") + "Sdk/IOSLib/SDK";
var sdkFolder = "SDK";
var sdkDir = Path.Combine(path, sdkFolder);
CopyOldLabFilesToNewLab(sdkPath, sdkDir);
//以Group方式添加文件夹引用到工程
//AddResourceGroupToiOSProject(path, proj, target, sdkFolder);
// 添加依赖库
proj.AddFrameworkToProject(target, "AdServices.framework", true);
proj.AddFrameworkToProject(target, "AppTrackingTransparency.framework", false);
proj.AddFrameworkToProject(target, "AppsFlyerLib.framework", false);
proj.AddFrameworkToProject(target, "Accounts.framework", false);
proj.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
proj.SetBuildProperty(target, "SWIFT_VERSION", "5.0");
//设置包名
proj.SetBuildProperty(target, "PRODUCT_BUNDLE_IDENTIFIER", "com.baplay.${PRODUCT_NAME:rfc1034identifier}");
proj.SetBuildProperty(target, "PRODUCT_NAME", "st");
//添加链接库
string linkerFlags = "$(inherited) -ObjC -lsqlite3.0 -lc++ -lstdc++ -lz -weak_framework Accelerate -weak-lSystem -weak_framework CoreMotion -weak-lSystem";
proj.SetBuildProperty(target, "OTHER_LDFLAGS", linkerFlags);
//string[] linkerFlagsToAdd = { "-lsqlite3.0", "-ObjC", "-lc++", "-lstdc++", "-lz", "-weak_framework", "Accelerate", "-weak-lSystem", "-weak_framework", "CoreMotion", "-weak-lSystem" };
//string[] linkerFlagsRemove = null;//删除的链接库
//proj.UpdateBuildProperty(target, "OTHER_LDFLAGS", linkerFlagsToAdd, linkerFlagsRemove);
string[] codeSignEntitlements = { "$(PROJECT_DIR)/SDK/Resource/Play.entitlements" };
proj.UpdateBuildProperty(target, "CODE_SIGN_ENTITLEMENTS", codeSignEntitlements, null);
//添加库引用路径
string[] FrameworkSearchPaths = { "$(PROJECT_DIR)/SDK/OtherLibs",
"$(PROJECT_DIR)/SDK/OtherLibs/GoogleSignIn_5.0.2",
"$(PROJECT_DIR)/SDK/OtherLibs/AF-iOS-SDK_v5.1" };
proj.UpdateBuildProperty(target, "FRAMEWORK_SEARCH_PATHS", FrameworkSearchPaths, null);
//添加资源引用路径
string[] LibrarySearchPaths = { "$(PROJECT_DIR)/SDK/OtherLibs/inMobi_5.0.1",
"$(PROJECT_DIR)/SDK/OtherLibs/OL113Tool",
"$(PROJECT_DIR)/SDK" };
proj.UpdateBuildProperty(target, "LIBRARY_SEARCH_PATHS", LibrarySearchPaths, null);
File.WriteAllText(projPath, proj.WriteToString());
// 修改Info.plist文件
var plistPath = Path.Combine(rootPath, "Info.plist");
var plist = new PlistDocument();
plist.ReadFromFile(plistPath);
//增加权限
plist.root.SetString("NSPhotoLibraryUsageDescription", "需要您的同意,才能访问相册");//
plist.root.SetString("NSMicrophoneUsageDescription", "需要您的同意,才能访问麦克风");
plist.root.SetString("NSCameraUsageDescription", "需要您的同意,才能访问相机");
plist.root.SetString("NSTrackingUsageDescription", "您同意App使用IDFA廣告識別碼來做個人最佳化廣告嗎?");
//增加键值对
plist.root.SetString("bundle id", "com.test.test");
plist.root.SetString("FacebookAppID", "819");
var schemes = plist.root.CreateArray("LSApplicationQueriesSchemes");
schemes.AddString("line");
schemes.AddString("fbapi");
schemes.AddString("fb-messenger-api");
schemes.AddString("fbauth2");
schemes.AddString("fbshareextension");
// 插入URL Scheme到Info.plsit(理清结构)
PlistElementArray urlArray = null;
if (!plist.root.values.ContainsKey("CFBundleURLTypes"))
urlArray = plist.root.CreateArray("CFBundleURLTypes");
urlArray = plist.root.values["CFBundleURLTypes"].AsArray();
var dict = urlArray.AddDict().CreateArray("CFBundleURLSchemes");
//插入dict
dict.AddString("stios");
dict.AddString("fb124442819");
// 应用修改
plist.WriteToFile(plistPath);
/// <summary>
/// 拷贝文件夹下所有文件到新目录下面
/// </summary>
/// <param name="sourcePath">l文件所在目录</param>
/// <param name="savePath">保存的目标目录</param>
/// <returns>返回:true-拷贝成功;false:拷贝失败</returns>
public static bool CopyOldLabFilesToNewLab(string sourcePath, string savePath)
if (!Directory.Exists(savePath))
Directory.CreateDirectory(savePath);
string[] labDirs = Directory.GetDirectories(sourcePath);//目录
string[] labFiles = Directory.GetFiles(sourcePath);//文件
if (labFiles.Length > 0)
for (int i = 0; i < labFiles.Length; i++)
if (!labFiles[i].Contains(".meta") && !labFiles[i].Contains(".DS_Store"))//排除文件
string fileName = Path.GetFileName(labFiles[i]);
File.Copy(Path.Combine(sourcePath, fileName), Path.Combine(savePath, fileName), true);
if (labDirs.Length > 0)
for (int j = 0; j < labDirs.Length; j++)
string fileName = Path.GetFileName(labDirs[j]);
Directory.GetDirectories(Path.Combine(sourcePath, fileName));
//递归调用
CopyOldLabFilesToNewLab(Path.Combine(sourcePath, fileName), Path.Combine(savePath, fileName));
catch (Exception)
return false;
return true;
//在工程文件添加资源文件夹引用,以 Create Group 形式加到工程文件
private static void AddResourceGroupToiOSProject(string xcodePath, PBXProject proj, string target, string resourceDirectoryPath)
string dirFullPath = Path.Combine(xcodePath, resourceDirectoryPath);
//添加文件引用
string[] files = Directory.GetFiles(dirFullPath);
foreach (string s in files)
string fileExtension = Path.GetExtension(s);
if (fileExtension.Equals(".DS_Store"))
continue;
string fileName = Path.GetFileName(s);
string targetFilePath = Path.Combine(resourceDirectoryPath, fileName);
string fileGuid = proj.AddFolderReference(targetFilePath, targetFilePath);
proj.AddFileToBuild(target, fileGuid);
//添加子文件夹
string[] subDirectorys = Directory.GetDirectories(dirFullPath);
foreach (string s in subDirectorys)
string fileName = Path.GetFileName(s);
string subDirPath = Path.Combine(resourceDirectoryPath, fileName);
string fileExtension = Path.GetExtension(s);
//mac os文件结构原因需要处理文件后缀,不然会变成文件夹,导致库无法正常识别
if (fileExtension.Equals(".xcassets")
|| fileExtension.EndsWith(".framework")
|| fileExtension.EndsWith(".xcframework")
|| fileExtension.EndsWith(".bundle")
|| fileExtension.EndsWith(".strings"))
string fileGuid = proj.AddFile(subDirPath, subDirPath);
proj.AddFileToBuild(target, fileGuid);
AddResourceGroupToiOSProject(xcodePath, proj, target, subDirPath);