Hey all, i am not familiar with Objecticve-C. I’m using it because I want to natively/correctly check if an app is installed on ios. I found the Objective-C snippet to see if an app is installed and understand needing a C-wrapper to basically have unity talk to the Objective-C script (mm file). Just don’t understand how to get the C-wrapper to get the Objective-C value I have within my mm script.
These are pretty good resources, but may be overkill for what I need:
Figured this would be a good place to get convos started with quick bits that the community can assist in. I know there are workarounds you can do in unity, they’re just not always the correct method/can be buggy at times.
Here’s my script:
// UnityPluginTest-1.mm
//
// Created by OJ on 7/13/16.
//
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
- (BOOL)isFBInstalledX;
@end
@implementation SampleClass
//Objective-C value I want
- (BOOL)isFBInstalledX {
return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"fb://"]];
}
@end
//C-wrapper that talks to Unity
extern "C"
{
bool isFBInstalled(){
// Need to get the Objective C BOOL value from above, my c# script will get this value once retrieved
//return -(Bool) isFBInstalledX value //--this doesn't work
//return ..... // I give up :(
}
}
[USER=116149]@Kurt-Dekker - Thanks for the reply. Yea, I know the c# stub I need on the unity end should look like this:
using UnityEngine;
using System.Runtime.InteropServices;
class GetMyOjbectiveCUnityPlugin : MonoBehaviour {
#if UNITY_IPHONE || UNITY_XBOX360
// On iOS and Xbox 360 plugins are statically linked into
// the executable, so we have to use __Internal as the
// library name.
[DllImport ("__Internal")]
private static extern bool isFBInstalled();
#else
// Other platforms load plugins dynamically, so pass the name
// of the plugin's dynamic library.
[DllImport ("PluginName")]
#endif
void Awake () {
bool FBStatus; //Assign value we recieve to this
// Calls the isFBInstalled function inside the plugin
FBStatus = isFBInstalled(); //returns the status of FB install in ObjC plugin
}
}
I know there is some sort of connectivity, because if you test with a fake bool value to return like below, it sends it back:
//C-wrapper that talks to Unity
extern "C"
{
bool isFBInstalled(){
// Need to get the Objective C BOOL value from above, my c# script will get this value once retrieved
return true; //this sends it back to the C# Unity script
}
}
Someone on stackoverflow got back to me with this:
// UnityPluginTest-1.mm
//
// Created by OJ on 7/13/16.
//
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
- (BOOL)isFBInstalledX;
@end
@implementation SampleClass
//Objective-C value I want
- (BOOL)isFBInstalledX {
return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"fb://"]];
}
@end
//C-wrapper that talks to Unity
extern "C"
{
bool isFBInstalled(){
// Need to get the Objective C BOOL value from above, my c# script will get this value once retrieved
//Stack overflow response
return [SimpleClass isFBInstalledX] //Has X-code compiling issues ("No Class Type")..Not sure if correct because it's a BOOL
}
}
Unfortunately this gives compiling issues in Xcode.
On the other hand this has no compiling issues when the method is written like this:
(BOOL)isFBInstalledX (with a “+”)
// UnityPluginTest-1.mm
//
// Created by OJ on 7/13/16.
//
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
+ (BOOL)isFBInstalledX;
@end
@implementation SampleClass
//Objective-C value I want
+ (BOOL)isFBInstalledX {
return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"fb://"]];
}
@end
//C-wrapper that talks to Unity
extern "C"
{
bool isFBInstalled(){
// Need to get the Objective C BOOL value from above, my c# script will get this value once retrieved
//Stack overflow response
return [SimpleClass isFBInstalledX] //This has no Xcode compiling issues, but returns nothing
}
}
unfortunately that returns nothing. Not sure if this may be close, but the return method is incorrect because we’re asking a BOOL return (returns yes/no), and not a bool (true/false)[/USER]
@Kurt-Dekker - Figured it out. Thanks again for your earlier inputs.
First - Apparently apple now requires you to place the URL schemes you’re planning to call in your info.plist -
“If your app is linked on or after iOS 9.0, you must declare the URL schemes you want to pass to this method. Do this by using the LSApplicationQueriesSchemes array in your Xcode project’s Info.plist file. For each URL scheme you want your app to use with this method, add it as a string in this array.” - here’s that resource Apple UIApplication-canOpenURL
In this case my strings would be fb, and yelp.
Second, feel free to use my attached scripts:
UnityPluginTest-1.mm (put this in your “Assets>plugins>ios” folder)
GetMyOjbectiveCUnityPlugin.cs ( this is the bridge. Place this in the same folder)
To call the FB/Yelp status from a script of your own you can do:
int testfb = GetMyOjbectiveCUnityPlugin().WegotFBApp(); //0 is No, 1 yes
int testyelp = GetMyOjbectiveCUnityPlugin().WegotYelpApp(); //0 is No, 1 yes
using UnityEngine;
using System.Runtime.InteropServices;
class GetMyOjbectiveCUnityPlugin : MonoBehaviour
{
#if UNITY_IOS
// On iOS and Xbox 360 plugins are statically linked into
// the executable, so we have to use __Internal as the
// library name.
[DllImport ("__Internal")]
private static extern int isFBInstalled();
[DllImport ("__Internal")]
private static extern int isYelpInstalled();
#else
// Other platforms load plugins dynamically, so pass the name
// of the plugin's dynamic library.
[DllImport("PluginName")]
#endif
public static int WegotFBApp()
{
int FBStatus = 0; //Assign value we recieve to this
// Calls the isFBInstalled function inside the plugin
FBStatus = isFBInstalled(); //returns the status of FB install in ObjC plugin
return FBStatus; // 0 is No, 1 is Yes
}
public static int WegotYelpApp()
{
int YelpStatus = 0; //Assign value we recieve to this
// Calls the isFBInstalled function inside the plugin
YelpStatus = isYelpInstalled(); //returns the status of FB install in ObjC plugin
return YelpStatus; // 0 is No, 1 is Yes
}
}
// UnityPluginTest-1.mm
// Created by OJ on 7/13/16.
// In unity, You'd place this file in your "Assets>plugins>ios" folder
//Objective-C Code
#import <Foundation/Foundation.h>
@interface SampleClass:NSObject
/* method declaration */
- (int)isYelpInstalledX;
- (int)isFBInstalledX;
@end
@implementation SampleClass
- (int)isYelpInstalledX
{
int param = 0;
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"yelp:"]])
{
param = 1; //Installed
}else{
param = 0; //Not Installed
}
return param;
}
- (int)isFBInstalledX
{
int param = 0;
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"fb:"]])
{
param = 1; //Installed
}else{
param = 0; //Not Installed
}
return param;
}
@end
//C-wrapper that Unity communicates with
extern "C"
{
int isFBInstalled()
{
SampleClass *status = [[SampleClass alloc] init];
return [status isFBInstalledX];
}
int isYelpInstalled()
{
SampleClass *status = [[SampleClass alloc] init];
return [status isYelpInstalledX];
}
}
Hi all,
I have gone through the above stuff and found very well.
But, I have some different scenario:
I have the c# code script like:
public class NativeAPI
{
[DllImport("__Internal")]
public static extern string[] getAllXRCloudScenes();
[DllImport("__Internal")]
public static extern string[] getAllSmartAssetsForXRCloudScene(string sceneId);
[DllImport("__Internal")]
public static extern void loadSmartAsset(string binaryId);
}
So, now I want to write the plugins in Objective-c++(.mm). Could anyone let me know how can I call the C# methods into the .mm plugins to get the array strings.
Basically, We almost have the void function like: “public static extern void sendUnityStateUpdate(string state);”
But I have now array of strings and unable to get the array if I tried like this:
In plugin .h file
Calling from native C back into C# is possible but has a lot of issues that have slowly changed over time as new capabilities are added. I have not bothered to keep up with those new issues and I always just call from C# into my C classes.
Thanks @Kurt-Dekker . I also try to calling from C# to Objective-C++(.mm) class. Therefore I have the C# script which having the arrays and that array I want to have in my .mm class somehow.
Not sure how to cross-platform marshal an array of strings. It’s likely possible, but I’m not really sure of the bookkeeping that might be involved.
I think I would probably just pack it into JSON or some other container and send it over as a single string, then unpack it on the native side, or else send it over one at a time with an index.
For my savedata on my KurtMaster2D games, I actually send each byte of “internal native state” over to the native side one byte at a time, and even the biggest block of data (about 256k) is still only a fraction of a second back and forth.
NOTE: I don’t think it’s possible to call ObjectionableC class methods directly due to name mangling, even static methods. I know this is the case for C++ methods (also due to name mangling) so instead you just call plain old C methods and use the extern "C" { } declarator on anything you want to call on the native side.
I don’t know about any of the ObjectionableC NS-nonsense stuff… each of those things have to be built in a very specific way or they fail. I would recommend sticking to simple scalar types and arrays of bytes.