Unity
编写iOS native的Plugin, 接入一些sdk什么的,需要和OC进行交互。下面已我写的ios支付插件为例,总结一下。
1)c#调用OC代码
首先需要在c#中声明OC的函数:
#if UNITY_IOS && !UNITY_EDITOR
[DllImport ("__Internal")]
private static extern void iosNativeInitPayCenter(string callbackGameObject, string callbackFunc);
[DllImport ("__Internal")]
private static extern void iosNativeRequestProducts(string storeName, string productIdListJson);
[DllImport("__Internal")]
private static extern void iosNativePay(string productId, long payId, string extendJsonData);
#endif
这些函数前面要加入
[
DllImport
(
"
__Internal
"
)]
,说明这是从dll导入的函数,并且来源于游戏本身的dll。函数必须声明为
private
static
extern
。
为了使用DllImport,需要 using System.Runtime.InteropServices;
而函数的参数则可以是string,long等基本类型,我没试过其他类型,但是string, long, int已经够用了,如果是复杂的对象,可以转成一个json字符串,在OC那边再解析成对象。
以上的函数声明我放在一个PayNativeBridge.cs的c#文件中,并且又添加了几个封装的方法,方便客户C#代码调用,例如:
public void Init(string callbackGameObject, string callbackFunc)
#if UNITY_IOS && !UNITY_EDITOR
iosNativeInitPayCenter(callbackGameObject, callbackFunc);
#endif
这是为了以后添加android等平台的代码,在客户代码中就可以无视平台的差异了。android的交互怎么处理以后再补充。
注意这个Init方法传人的参数,是一个GameObject对象的名称和该对象的一个函数名称,这个函数用于接受从OC代码传入的调用,因此叫callbackFunc。
2) OC实现import的函数
前面声明的这些DllImport的函数,需要在OC中实现,需要注意的是,函数的签名要符合C的调用规范,因此要加上extern "C"。例如:
static NSString *s_callbackGameObject;
static NSString *s_callbackFunc;
#if defined(_cplusplus)
extern "C"{
#endif
void iosNativeInitPayCenter(const char* callbackGameObject, const char* callbackFunc)
s_callbackGameObject = [NSString stringWithUTF8String: callbackGameObject];
s_callbackFunc = [NSString stringWithUTF8String: callbackFunc];
#if defined(_cplusplus)
#endif
这个函数的参数类型需要用c的类型,比如string要写成const char*。c#会自动识别到签名一致的函数,这点可比java的native代码调用方便了很多啊。这个函数里面我保存了传进来的
callbackGameObject和callbackFunc。这两个字符串是用来从OC回调C#的,下面就说一下。
3)OC回调Unity C#代码
当C#调用dllImport的OC代码后,OC代码进行一些处理,需要向C#返回处理的结果,这就需要使用Unity提供的发送回调事件的方法。从Unity导出的xcode工程中,已经包含了必要的头文件,其中UnityInterface.h中声明了一个方法:
void UnitySendMessage(const char* obj, const char* method, const char* msg);
在OC中使用这个方法可以向C#发送事件,回调C#的代码。参数obj就是上面保存的GameObject的名字,method即为回调函数名字,msg是发送的消息参数。需要说明的是,回调函数可以存在于GameObject所挂接的任意脚本组件上,但是函数签名必须符合public void Foo(string param)的格式。也就是说只能向C#脚本发送一个string参数。不过一个string已经够用了,通常的解决方案就是把需要发送的参数打包成一个json字符串。
下面是我封装一个方法,用于把一个整形的msgCode和一个data对象发送到Unity:
-(void)callbackToUnity:(int) msgCode :(id)data
NSMutableDictionary *dictRoot = [NSMutableDictionary dictionaryWithCapacity:1];
NSNumber* msg = [NSNumber numberWithInt:msgCode];
[dictRoot setObject:msg forKey:@"msg"];
if(data!=nil){
[dictRoot setObject:data forKey:@"data"];
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictRoot options:kNilOptions error:&error];
NSString *jsonStr =[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
UnitySendMessage([s_callbackGameObject UTF8String], [s_callbackFunc UTF8String], [jsonStr UTF8String]);
以下是从storeKit获取产品列表的方法,获取后发送给Unity:
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
NSLog(@"AppleIAPDelegate: Received products request respose");
if ([response.invalidProductIdentifiers count])
NSLog(@"Got invalid ones: %@", response.invalidProductIdentifiers);
NSArray* products = response.products;
NSUInteger productCount = [products count];
NSLog(@"Procut Count:%lu", (unsigned long)productCount);
NSMutableDictionary *outputProdcuts = [NSMutableDictionary dictionaryWithCapacity:productCount];
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
for(int i=0; i<productCount; i++)
SKProduct *product = (SKProduct*)[products objectAtIndex:i];
[numberFormatter setFormatterBehavior:NSNumberFormatterBehaviorDefault];
[numberFormatter setNumberStyle:NSNumberFormatterCurrencyStyle];
[numberFormatter setLocale:product.priceLocale];
NSString *formattedString = [numberFormatter stringFromNumber:product.price];
[outputProdcuts setObject:formattedString forKey:[product productIdentifier]];
//save products
[mProducts setObject:product forKey:[product productIdentifier]];
//callback to unity
[self callbackToUnity:STORE_GET_PRODUCTS_SUCCESS :outputProdcuts];
if (request == mCurrentProductRequest)
mCurrentProductRequest = nil;
NSLog(@"AppleIAPDelegate: Warning: mCurrentProductRequest not responsed first!");
Unity编写iOS native的Plugin, 接入一些sdk什么的,需要和OC进行交互。下面已我写的ios支付插件为例,总结一下。1)c#调用OC代码首先需要在c#中声明OC的函数:#if UNITY_IOS &amp;&amp; !UNITY_EDITOR [DllImport ("__Internal")] private static...
找到GetShortPathName的方法签名,
DWORD GetShortPathName(LPCTSTR tpszLongPath,TPTSTR lpszShortPath,DWORD cchBuffer);
非托管及托管数据类型对应关系:
LPCTSTR String
LPTSTR StringBuilder
DWORD int
DllImport的导入规则:
1、方法名与Win API完全一样。如果在C#中调用时显示完全不同的方法名称,则需要引入EntryPoint属性,使用别名显示。
2、函数除需要DllImport类修饰符外,
Unity中免不了需要C#和OC或者Java代码交互,最近发现与OC交互的部分代码有兼容问题,在64位机器上测试没问题,不过在32位机器上测试就必然奔溃,最后定位到了一个方法里的long参数,因为它前面的参数都没问题,它和它之后的参数内容和正确的内容完全对不上。
//C#
[DllImport ("__Internal")]
private static extern void _tes...
前言在unity中接入sdk或者定制一些功能时,需要调用系统接口。iphone手机实际操作中,也就是Unity与iOS相互调用。我们在Unity中使用c#,iOS中使用Objective-C(以下称为oc)。
下面介绍他们如何相互调用。
对于非科班出身的程序来说,在没有学过C和OC的情况,用unity开发iOS相关的功能,是非常痛苦的。简单写一下自己遇到的,并且没有百度到的坑。
1、C#给OC传递字典
一般流程是,C#调用C,C调用OC,但是C没有字典。处理方法,用结构体数组做中转。核心,结构体数组转换字典。
C#层代码
using System.Runtime.InteropServices...
注意事项:
OC与C++对象在内存管理上是不一样的。所以我们无法直接将一个OC对象直接赋值给一个C++对象,或者相反。
OC与C++都支持指针,可以通过指针进行桥接。例如在一个C++类中声名一个OC的指针。
clang可以通过程序文件的后缀名选择不同的编译器对其进行编译。如文件后缀名是.m,它会使用OC编译器;如果是.mm,它会使用Object-C++编译器。
OC调用C语言:
// 方法一:c语言可以直接在OC的类中写方法:
- (void)playvideobtn{
// 调用c语言方法:
unity调用OC的方法我们需要用到中间语言c作为通信。整个过程是:c#调用c,c调用oc。
首先我们在建一个unity的工程,新建一个叫sdk的c#脚本,敲如下代码:(注:
一定要引入using System.Runtime.InteropServices;
DllImport 属性其实就是调用dll的意思,
private static extern void _Bt
要想在Unity界面上打开一个原生的UIWebView需要在unity界面上覆盖一个新的UIView及其UIViewController,原理是获取当前的unity场景(其实在IOS中也是一个UIViewController)的UIViewController,然后添加子页面和子控制器:
实现步骤如下: