I'm attempting to write my first unity script. This is the code for a file called TestPlugin.cs that is located in Assets/Plugins:
using UnityEngine;
using System.Runtime.InteropServices;
public class TestPlugin : MonoBehaviour
{
[DllImport ("__Internal")]
private static extern int getString ();
public static void Awake () {
print (getString ());
}
}
This is the code for two files that I import into the generated xCode project's classes folder:
TestPlugin.h:
#import <Foundation/Foundation.h>
#interface TestPlugin : NSObject
-(int)getString;
#end
TestPlugin.m:
#import "TestPlugin.h"
#implementation TestPlugin
- (id)init
{
self = [super init];
if (self) {
// Initialization code here.
}
return self;
}
- (int)getString
{
return 7;
}
#end
Finally this is the javascript file that sits inside the Asset folder.
TestPluginTest.js:
function Update ()
{
TestPlugin.Awake ();
}
Also, please note that i'm not necessarily expecting this all to work, just to compile at this point (though extra pointers and tips are welcome)
The error I get in xCode when trying to build onto iPhone (actual device) is this:
Undefined symbols for architecture armv7: "_getString", referenced
from:
RegisterMonoModules() in RegisterMonoModules.o ld: symbol(s) not found for architecture armv7 collect2: ld returned 1 exit status
"_getString", referenced from:
RegisterMonoModules() in RegisterMonoModules.o
ld: symbol(s) not found for architecture armv7
collect2: ld returned 1 exit status
I'm stumped! Thanks in advance!
I think the problem lies in the Obj-C interface because the linker does not know how to handle the signature. When I connected a self written library I designed the interface to contain pure C code only:
interface.h
#ifdef __cplusplus
extern "C" {
#endif
int getString();
#ifdef __cplusplus
}
#endif
interface.c:
int getString() {
// do something
}
Maybe useful blog postings:
iPhone & Unity3D: Integrating 3rd Party Static Libraries in Unity3D Generated XCode Projects
Unity Native Plugins: OS X
Clever Martian's Blog - An Experiment with iPhone Native UI and Unity 3 Pro
Related
Say I have a class like this
// DummyObject.h
#interface DummyObject : NSObject
- (instancetype)initWithFoo:(NSString *)foo
NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
#end
and
// DummyObject.m
inline void
foobar() {}
static inline void
static_foobar() {}
#implementation DummyObject
- (instancetype)initWithFoo:(NSString *)foo
{
if (self = [super init])
{
// Undefined symbols for architecture x86_64:
// "_foobar", referenced from:
// -[DummyObject initWithFoo:] in DummyObject.o
foobar();
static_foobar(); // Works as expected
}
return self;
}
#end
My understanding about inline is that it simply suggest the compiler to embed the function body into the calling code instead of executing an actual call. And static refers to the scope, which means I can only use this very function inside the file that defines it.
Update 1:
According to trungduc's comment, "inline foobar" works after change DummyObject.m to DummyObject.mm.
So my current conclusion is
If DummyObject is compiled as Objective-C(.m), then "inline foobar" won't work
If DummyObject is compiled as Objective-C++(.mm), then "inline foobar" works fine
If I delete the "inline" keyword, then "foobar" works fine in both Objective-C and Objective-C++
"static inline static_foobar" always works
This is quite confusing, I've checked the Clang documentation with no luck. This has been in my head for about 2 days, any suggestions will help...
I am using FXForm Library and want to get data from my Swift file in Objective C file function.
Demo Project Link
Swift Code Implimnetation:
let fontName = "HelveticaNeue"
let fontSizeLarge:CGFloat = 14.0
var hiddenElementFromFormIndex = [Int]()
//fx form variables
#objc class FXFormVariables : NSObject {
public override init() {}
class func FXFontName() -> String { return fontName }
class func FXFontSize() -> CGFloat { return fontSizeLarge }
class func FXHiddenCell() -> NSArray { return hiddenElementFromFormIndex as NSArray }
}
In Objective C file, I am getting error when we write below like:
NSArray *hideArray = [FXFormVariables FXHiddenCell];
I created the bridge header file correctly and Target Membership is checked in the Objective C file.
Error I am getting:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$__TtCC13Social_Engine11AppDelegate15FXFormVariables", referenced from:
objc-class-ref in FXForms.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Architectures and Valid Architectures are:
armv7 and armv64
To use Swift class inside Objective-C file you need to import Xcode-generated header file in your Objective-C file.
#import "ProductModuleName-Swift.h"
I created a Test project with the same name.
Swift File:
//
// FXFormVariables.swift
// Test
//
// Created by Puneet Sharma2 on 12/07/17.
// Copyright © 2017 com.puneet.sh2525. All rights reserved.
//
import Foundation
import UIKit
let fontName = "HelveticaNeue"
let fontSizeLarge:CGFloat = 14.0
var hiddenElementFromFormIndex = [Int]()
//fx form variables
#objc class FXFormVariables : NSObject {
public override init() {}
class func FXFontName() -> String { return fontName }
class func FXFontSize() -> CGFloat { return fontSizeLarge }
class func FXHiddenCell() -> NSArray { return hiddenElementFromFormIndex as NSArray }
}
Objective-C File
#import "ABC.h"
#import "Test-Swift.h"
#implementation ABC
- (void)drawRect:(CGRect)rect {
NSArray *hideArray = [FXFormVariables FXHiddenCell];
}
You can read more about it here.
Literally I spent hours trying to figure out why this was happening with one of my swift files that i was importing into my Objc codebase, and the real reason was due to the use of a nested class.
Such as:
#objc public class MyClass {
#objc public class SecondClass {}
}
And if I tried using SecondClass in my objective-c code, I would the Apple Mach O-Link errors of death. So the solution was to de-nest the class you want to use.
#objc public class MyClass {}
#objc public class SecondClass {}
I've written a custom struct in a separate header file. It looks something like this
typedef struct RequestSpecifics {
BOOL includeMetaData;
BOOL includeVerboseData;
} RequestSpecifics;
Now I want to make a custom 'make' method, similar to the CoreLocation struct CLLocationCoordinate2 CLLocationCoordinate2DMake method.
I've tried two different ways. While both ways give no errors in the .h file, I do get errors when I want to use the make method.
Method 1:
extern RequestSpecifics RequestSpecificsMake(BOOL includeMetaData, BOOL includeVerboseData);
Throws:
Apple Mach-O Linker
"_RequestSpecificsMake", referenced from:
Error Linker command failed with exit code 1 (use -v to see invocation)
Method 2:
extern RequestSpecifics RequestSpecificsMake(BOOL includeMetaData, BOOL includeVerboseData) {
RequestSpecifics specifics;
specifics.includeMetaData = includeMetaData;
specifics.includeVerboseData = includeVerboseData;
return specifics;
}
Throws:
Apple Mach-O Linker
Error Linker command failed with exit code 1 (use -v to see invocation)
Usage example:
RequestSpecificsMake(NO, NO)
I've checked all common solutions for the Apple Macho-Linker error but nothing seems to work or the solutions are not relevant.
So how do I correctly implement the 'make' method for a struct?
So apparently method 2 should be the implementation and it should not be in the .h file. Naturally, I need a .m file as well. This should be the correct way to do it:
.h file
RequestSpecifics RequestSpecificsMake(BOOL includeMetaData, BOOL includeVerboseData);
.m file
RequestSpecifics RequestSpecificsMake(BOOL includeMetaData, BOOL includeVerboseData) {
RequestSpecifics specifics;
specifics.includeMetaData = includeMetaData;
specifics.includeVerboseData = includeVerboseData;
return specifics;
}
In the end I had to combine both methods! Also, by the looks of it, the extern keyword is not required.
Why dont you try
static inline instead of extern
static inline RequestSpecifics RequestSpecificsMake(BOOL includeMetaData, BOOL includeVerboseData) {
RequestSpecifics specifics;
specifics.includeMetaData = includeMetaData;
specifics.includeVerboseData = includeVerboseData;
return specifics;
}
or if you want to use extern then you need to write it in .m file.
Can't understand the error.
duplicate symbol _currentCount in:
/Users/selim/Library/Developer/Xcode/DerivedData/iXEN-aimjepotqgbjmlaghqjovwpsngvx/Build/Intermediates/iXEN.build/Debug-iphonesimulator/iXEN.build/Objects-normal/i386/Server.o
/Users/selim/Library/Developer/Xcode/DerivedData/iXEN-aimjepotqgbjmlaghqjovwpsngvx/Build/Intermediates/iXEN.build/Debug-iphonesimulator/iXEN.build/Objects-normal/i386/Alerts.o
ld: 1 duplicate symbol for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
1、if you declare the currentCount in .h file and include it in two .m file.
Add extern in front of currentCount declaration in .h file.
example
extern int currentCount;
2、if you declare the currentCount in two .m file.
And static in front of currentCount in .m file
example
static int currentCount
One more thing, variable declare after #implementation doesn't belong to that class , it is global value.
#interface Obj : NSObject
#end
#implementation Obj
int a = 0 ; // a declare in Obj class
#end
#interface Obj2 : NSObject
#end
#implementation Obj2
- (id)init
{
self = [super init] ;
if (self) {
a = 1 ; // you can access it in Obj2 class
}
return self ;
}
#end
Add Quartzcore framework
or check the file you don't have any duplicate file name in project.i think you add two projects thats why this error is occur.
Check it may you write a "#import file.m" instead of "#import file.h". So, In Compiles Resource will duplicate symbol file.o.
You may need to remove the duplicates in Targets Build Phases under the Compiled Sources grouping.
I have the Dragon Mobile SDK running nicely on Windows Phone 7 and I would like to get the equivalent functionality working for iOS. Since the SDK wraps the microphone, it's not really possible to use the .NET assemblies in my MonoTouch project (even if I did have the source). It appears that the best way to do this is to create a binding library (as Miguel describes here).
It sure seems like a lot of work though, and I would love to reuse as opposed to reinventing the wheel if someone's done it already...
Here are some more details for how I got this to work.
I downloaded the binding sample. You may be tempted to skip this step, but you really have to start with this project if you want to get this to work.
I created an objective-c library with Xcode (which I called SpeechKitLibrary) that has a dual purpose - one is to define the SpeechKitApplicationKey (which is an extern dependency that SpeechKit needs):
const unsigned char SpeechKitApplicationKey[] = {...};
and the other is to define a class which utilizes the SpeechKit framework, and links with it. (in Xcode, add the SpeechKit framework in the frameworks section of the project).
The .m file I wrote looks something like this... (you can figure out the .h file - super simple). I'm not 100% sure you need all of this, but I wanted to make sure the static archive library that came out of this step would import the right symbols. You may be able to avoid this somehow, but in my experiments I found that I needed to do something like this...
// the SpeechKitWrapper isn't actually used - rather, it is a way to exercise all the API's that
// the binding library needs from the SpeechKit framework, so that those can be linked into the generated .a file.
#implementation SpeechKitWrapper
#synthesize status;
- (id)initWithDelegate:(id <SKRecognizerDelegate>)delegate
{
self = [super init];
if (self) {
del = delegate;
[self setStatus:#"initializing"];
SpeechKit setupWithID:#"NMDPTRIAL_ogazitt20120220010133"
host:#"sandbox.nmdp.nuancemobility.net"
port:443
useSSL:NO
delegate:nil];
NSString *text = [NSString stringWithFormat:#"initialized. sessionid = %#", [SpeechKit sessionID]];
[self setStatus:text];
SKEarcon* earconStart = [SKEarcon earconWithName:#"beep.wav"];
[SpeechKit setEarcon:earconStart forType:SKStartRecordingEarconType];
voiceSearch = [[SKRecognizer alloc] initWithType:SKDictationRecognizerType
detection:SKLongEndOfSpeechDetection
language:#"en_US"
delegate:delegate];
text = [NSString stringWithFormat:#"recognizer connecting. sessionid = %#", [SpeechKit sessionID]];
[self setStatus:text];
}
return self;
}
#end
I then compiled/linked this static archive for the three different architectures - i386, arm6, and arm7. The Makefile in the BindingSample is the template for how to do this. But the net is that you get three libraries - libSpeechKitLibrary-{i386,arm6,arm7}.a. The makefile then creates a universal library (libSpeechKitLibraryUniversal.a) using the OSX lipo(1) tool.
Only now are you ready to create a binding library. You can reuse the AssemblyInfo.cs in the binding sample (which will show how to create an import on the universal library for all architectures - and will drive some compile flags)...
[assembly: LinkWith ("libSpeechKitLibraryUniversal.a", LinkTarget.Simulator | LinkTarget.ArmV6 | LinkTarget.ArmV7, ForceLoad = true)]
You compile the ApiDefinition.cs file with btouch as per the Makefile (I think I needed to repeat some of the info in StructsAndEnums.cs to make it work). Note - the only functionality I didn't get to work is the "SetEarcon" stuff - since this is an archive library and not a framework, I can't bundle a wav as a resource file... and I couldn't figure out how to get the SetEarcon method to accept a resource out of my app bundle.
using System;
using MonoTouch.Foundation;
namespace Nuance.SpeechKit
{
// SKEarcon.h
public enum SKEarconType
{
SKStartRecordingEarconType = 1,
SKStopRecordingEarconType = 2,
SKCancelRecordingEarconType = 3,
};
// SKRecognizer.h
public enum SKEndOfSpeechDetection
{
SKNoEndOfSpeechDetection = 1,
SKShortEndOfSpeechDetection = 2,
SKLongEndOfSpeechDetection = 3,
};
public static class SKRecognizerType
{
public static string SKDictationRecognizerType = "dictation";
public static string SKWebSearchRecognizerType = "websearch";
};
// SpeechKitErrors.h
public enum SpeechKitErrors
{
SKServerConnectionError = 1,
SKServerRetryError = 2,
SKRecognizerError = 3,
SKVocalizerError = 4,
SKCancelledError = 5,
};
// SKEarcon.h
[BaseType(typeof(NSObject))]
interface SKEarcon
{
[Export("initWithContentsOfFile:")]
IntPtr Constructor(string path);
[Static, Export("earconWithName:")]
SKEarcon FromName(string name);
}
// SKRecognition.h
[BaseType(typeof(NSObject))]
interface SKRecognition
{
[Export("results")]
string[] Results { get; }
[Export("scores")]
NSNumber[] Scores { get; }
[Export("suggestion")]
string Suggestion { get; }
[Export("firstResult")]
string FirstResult();
}
// SKRecognizer.h
[BaseType(typeof(NSObject))]
interface SKRecognizer
{
[Export("audioLevel")]
float AudioLevel { get; }
[Export ("initWithType:detection:language:delegate:")]
IntPtr Constructor (string type, SKEndOfSpeechDetection detection, string language, SKRecognizerDelegate del);
[Export("stopRecording")]
void StopRecording();
[Export("cancel")]
void Cancel();
/*
[Field ("SKSearchRecognizerType", "__Internal")]
NSString SKSearchRecognizerType { get; }
[Field ("SKDictationRecognizerType", "__Internal")]
NSString SKDictationRecognizerType { get; }
*/
}
[BaseType(typeof(NSObject))]
[Model]
interface SKRecognizerDelegate
{
[Export("recognizerDidBeginRecording:")]
void OnRecordingBegin (SKRecognizer recognizer);
[Export("recognizerDidFinishRecording:")]
void OnRecordingDone (SKRecognizer recognizer);
[Export("recognizer:didFinishWithResults:")]
[Abstract]
void OnResults (SKRecognizer recognizer, SKRecognition results);
[Export("recognizer:didFinishWithError:suggestion:")]
[Abstract]
void OnError (SKRecognizer recognizer, NSError error, string suggestion);
}
// speechkit.h
[BaseType(typeof(NSObject))]
interface SpeechKit
{
[Static, Export("setupWithID:host:port:useSSL:delegate:")]
void Initialize(string id, string host, int port, bool useSSL, [NullAllowed] SpeechKitDelegate del);
[Static, Export("destroy")]
void Destroy();
[Static, Export("sessionID")]
string GetSessionID();
[Static, Export("setEarcon:forType:")]
void SetEarcon(SKEarcon earcon, SKEarconType type);
}
[BaseType(typeof(NSObject))]
[Model]
interface SpeechKitDelegate
{
[Export("destroyed")]
void Destroyed();
}
[BaseType(typeof(NSObject))]
interface SpeechKitWrapper
{
[Export("initWithDelegate:")]
IntPtr Constructor(SKRecognizerDelegate del);
[Export("status")]
string Status { get; set; }
}
}
You now have an assembly that can be referenced by your monotouch application project. The important thing now is to remember to link with all the frameworks that are dependencies (not only SpeeckKit, but also SK's dependencies) - you do this by passing mtouch some additional arguments:
-gcc_flags "-F<insert_framework_path_here> -framework SpeechKit -framework SystemConfiguration -framework Security -framework AVFoundation -framework AudioToolbox"
That's all, folks! Hope this was helpful...
If anyone (kos or otherwise) gets the SetEarcon method to work, please post a solution :-)
Nuance's SDK Agreement is not permissive enough for anyone to even publish bindings for their iOS SDK for use with MonoTouch. But the library itself should work just fine.
That being said, the SDK has only a handful of types to map and would be fairly trivial to RE-do the work anyone else might have already done. You can check out how to bind assemblies using the reference guide here:
http://docs.xamarin.com/ios/advanced_topics/binding_objective-c_types
There's also a BindingSample project that helps users better understand how to bind native components using btouch:
https://github.com/xamarin/monotouch-samples/tree/master/BindingSample
Thanks again Anuj for your answer. I thought I'd leave a tip or two about how to do this. The binding library wasn't difficult to build (still tweaking it but it's not a difficult task).
The more obscure part was figuring out how to get the SpeechKit framework linked. The samples only show how to link a .a or .dylib. After spending a little time with the ld(1) man page on OSX, it looks like the correct ld (and therefore gcc) arguments for linking with a framework are the following:
-gcc_flags "-F<insert_framework_path_here> -framework SpeechKit"
You put this in a textbox in the project properties - under Build :: iPhone Build :: Additional mtouch arguments
Note that -L doesn't work because this isn't a library; also note that -force_load and -ObjC referenced here don't appear necessary because, again, this is a framework and not a library.