Adding a Native iOS Library to a MAUI Project - objective-c

I develop an app with MAUI (only for iOS), and need to use a library which was written with Xamarin.iOS and it has a static native library (a file)
I could not use the xamarin project, so I just created a new maui class library project and move the code to this project and added a file as a native library
<ItemGroup>
<ObjcBindingNativeLibrary Include="libAreteUart\a" />
</ItemGroup>
And then I added this class library to my maui app project and when I try to build it, I get the following errors
/usr/local/share/dotnet/packs/Microsoft.iOS.Sdk/16.2.1007/targets/Xamarin.Shared.Sdk.targets(3,3):
Error: clang++ exited with code 1:
Undefined symbols for architecture arm64:
"_OBJC_CLASS_$_ComboBarcodeApi", referenced from:
objc-class-ref in registrar.o
"_OBJC_CLASS_$_ComboNFCApi", referenced from:
objc-class-ref in registrar.o
"_OBJC_CLASS_$_ComboRFIDApi", referenced from:
objc-class-ref in registrar.o
"_OBJC_CLASS_$_CommonDevice", referenced from:
objc-class-ref in registrar.o
"_OBJC_CLASS_$_CommonReaderInfo", referenced from:
objc-class-ref in registrar.o
"_OBJC_CLASS_$_RcpApi", referenced from:
objc-class-ref in registrar.o
"_OBJC_CLASS_$_SDeviceApi", referenced from:
objc-class-ref in registrar.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation) (TestMauiApp)
As I understand, there is an issue with the Register attribute. Here is my example class
PS: by the way I tried, don't link, only SDK and link all options but got the same error
// Token: 0x02000003 RID: 3
[Register("ComboBarcodeApi", true)]
public class ComboBarcodeApi : SDeviceApi
{
// Token: 0x17000001 RID: 1
// (get) Token: 0x06000059 RID: 89 RVA: 0x0000206E File Offset: 0x0000026E
public override NativeHandle ClassHandle
{
get
{
return ComboBarcodeApi.class_ptr;
}
}
// Token: 0x0600005A RID: 90 RVA: 0x00002078 File Offset: 0x00000278
[CompilerGenerated]
[EditorBrowsable(EditorBrowsableState.Advanced)]
[Export("init")]
public ComboBarcodeApi() : base(NSObjectFlag.Empty)
{
base.IsDirectBinding = (base.GetType().Assembly == Messaging.this_assembly);
if (base.IsDirectBinding)
{
base.InitializeHandle(Messaging.IntPtr_objc_msgSend(base.Handle, Selector.GetHandle("init")), "init");
return;
}
base.InitializeHandle(Messaging.IntPtr_objc_msgSendSuper(base.SuperHandle, Selector.GetHandle("init")), "init");
}
.....
}
I found a similar issue here but no answer or workaround
https://github.com/xamarin/xamarin-macios/issues/17196

Related

Resolving third party cocoapod dependencies in Kotlin MPP

I am trying to setup a tracking library written in Kotlin Multiplatform to support all our mobile clients.
Tests for Android went well (integrating snowplow via gradle).
I also managed to integrate Snowplow via cocoapods into the MPP.
kotlin {
...
cocoapods {
...
pod("SnowplowTracker") {
version = "~> 1.3.0"
}
}
And wrote following class in the X64 sourceset:
import cocoapods.SnowplowTracker.*
import com.tracking.domain.model.*
class X64Tracker {
private val tracker: SPTracker
init {
val emitter = SPEmitter.build {
it?.setUrlEndpoint("our.staging.endpoint")
it?.setProtocol(SPProtocol.SPProtocolHttps)
}
tracker = SPTracker.build {
emitter?.let { spEmitter -> it?.setEmitter(spEmitter) }
it?.setBase64Encoded(false)
it?.setSubject(SPSubject(platformContext = true, andGeoContext = true))
it?.setAppId("MPP.test")
it?.setApplicationContext(true)
}
}
fun trackSomething() {
track(
eventData = getEventData(
name = "MPP_test_event",
appArea = EventArea.Lifecycle,
action = EventAction.Check,
objectType = EventObjectType.Device,
source = EventSource.Client,
screenName = EventScreenName.Congratulations,
), contexts = emptyList()
)
}
private fun track(eventData: SPSelfDescribingJson, contexts: List<SPSelfDescribingJson?>) {
try {
val yo = SPSelfDescribing.build {
it?.setEventData(eventData)
it?.setContexts(contexts.toMutableList())
}
tracker.track(yo)
} catch (e: IllegalStateException) {
print("snowplow was not yet initialized when the following event occurred: $eventData")
}
}
private fun getEventData(
name: String,
appArea: EventArea,
action: EventAction,
objectType: EventObjectType,
source: EventSource,
screenName: EventScreenName,
) = SPSelfDescribingJson(
SCHEMA_EVENT, mapOf(
PROPERTY_EVENT_NAME to name,
PROPERTY_APP_AREA to appArea.serializedName,
PROPERTY_ACTION to action.serializedName,
PROPERTY_OBJECT_TYPE to objectType.serializedName,
PROPERTY_SOURCE to source.serializedName,
PROPERTY_SCREEN_NAME to screenName.serializedName,
)
)
}
Which is compiling and building our .framework files fine. Here is how we do that:
tasks.register<org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask>("debugFatFramework") {
baseName = frameworkName + "_sim"
group = "Universal framework"
description = "Builds a universal (fat) debug framework"
from(iosX64.binaries.getFramework("DEBUG"))
}
tasks.register<org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask>("releaseFatFramework") {
baseName = frameworkName + "_arm"
group = "Universal framework"
description = "Builds a universal (release) debug framework"
from(iosArm64.binaries.getFramework("RELEASE"))
}
Afterwards we combine this into an .xcframework file using following command:
xcrun xcodebuild -create-xcframework \
-framework tracking_arm.framework \
-framework tracking_sim.framework \
-output tracking.xcframework
We use Carthage to integrate it into our main app, but as soon I try to build the iOS project following error pops up:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_SPSelfDescribing", referenced from:
objc-class-ref in tracking_sim(result.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
The weird thing: No matter which version of Snowplow I define in the cocoapods block - the syntax in my class does not need to change. Even updating to Snowplow 2.x doesn't require me to get rid of the SP prefixes.
I am not sure how to continue at all and appreciate any help.
The following:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_SPSelfDescribing", referenced from:
objc-class-ref in kaiaTracking_sim(result.o)
ld: symbol(s) not found for architecture x86_64
That says the linker can't find SPSelfDescribing. I assume SPSelfDescribing is part of SnowplowTracker. You'll need to add SnowplowTracker to the iOS app.
If you were using Cocoapods to integrate Kotlin into your iOS project, the podspec generated would include SnowplowTracker as a dependency.
Since you are not using Cocoapods, you need to include it yourself. We recently had to figure out Carthage for a client. I would highly recommend moving to SPM or Cocoapods for a number of reasons, but that's a different discussion. To add SnowplowTracker with Carthage, add this to your Cartfile:
github "snowplow/snowplow-objc-tracker" ~> 1.3
Then when you update Carthage, add that to your iOS project. The linker will be able to find it.
To be clear, the Undefined symbols for architecture x86_64 error isn't complaining about Kotlin. It's saying it can't find SnowplowTracker, which you need to add to the iOS project.

Build WORHP on osx

I would like to try worhp with scip. I first tried building the examples by using Makefile give in worhp 1.14. I get this message when compiling with Makefile:
ld: warning: ignoring file lib/libworhp.so, building for macOS-x86_64 but attempting to link with file built for unknown-unsupported file format ( 0x7F 0x45 0x4C 0x46 0x02 0x01 0x01 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 )
Undefined symbols for architecture x86_64:
"_CheckWorhpVersion", referenced from:
_main in c-example.o
"_DoneUserAction", referenced from:
_main in c-example.o
"_GetUserAction", referenced from:
_main in c-example.o
"_InitParams", referenced from:
_main in c-example.o
"_IterationOutput", referenced from:
_main in c-example.o
"_ReadParamsNoInit", referenced from:
_main in c-example.o
"_StatusMsg", referenced from:
_main in c-example.o
"_Worhp", referenced from:
_main in c-example.o
"_WorhpFidif", referenced from:
_main in c-example.o
"_WorhpFree", referenced from:
_main in c-example.o
"_WorhpInit", referenced from:
_main in c-example.o
"_WorhpPreInit", referenced from:
_main in c-example.o
ld: symbol(s) not found for architecture x86_64
Is there any way to use the library on Mac osx?

Kotlin native interop linker could not find framework

I'm trying to use cocoapods framework in Kotlin Multiplatform project.
So I
added framework to Pods file.
ran pod install.
created .def file
added cinterop config in build.gradle
./gradlew cinteropFirebaseIos runs successfully. It generates .klib so I can see classes in kotlin code.
But when I'm trying to run iOS app build fails with message:
Showing Recent Messages
> Task :app:linkDebugFrameworkIos
ld: framework not found FirebaseDatabase
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld invocation reported errors
Here is my config in build.gradle
fromPreset(presets.iosX64, 'ios') {
compilations.main {
outputKinds('FRAMEWORK')
cinterops {
firebase {
def proj = "${System.getProperty("user.home")}/Projects/kmpp"
def pods = "${proj}/iosApp/Pods"
defFile "${proj}/app/src/iosMain/c_interop/libfirebase.def"
includeDirs "${pods}/Firebase",
"${pods}/Firebase/CoreOnly/Sources",
"${pods}/FirebaseAnalytics/Frameworks/FirebaseAnalytics.framework/Headers"
}
}
}
}
here is my .def file:
language = Objective-C
headers = /Users/oleg/Projects/klug/crckalculator/iosApp/Pods/FirebaseCore/Firebase/Core/Public/FIRApp.h /Users/oleg/Projects/klug/crckalculator/iosApp/Pods/FirebaseDatabase/Firebase/Database/Public/FIRDatabase.h /Users/oleg/Projects/klug/crckalculator/iosApp/Pods/FirebaseCore/Firebase/Core/Public/FirebaseCore.h
compilerOpts = -framework FirebaseDatabase
linkerOpts = -framework FirebaseDatabase
How can I figure out what is wrong ? Did I miss something in .def file ? In build.gradle ?
There are two problematic moments here:
full paths to C headers in .def file are usually not desirable, instead passing includeDirs to Firebase installation, like in https://github.com/JetBrains/kotlin-native/blob/c7c566ce0f12221088a8908b6dc8e116c56a931b/samples/gtk/build.gradle#L22 would be helpful
linking problem comes from the similar issue - linker just got no idea where to look for framework libraries, so passing to compilations.main.linkerOpts smth like -F /Users/oleg/Projects/klug/crckalculator/iosApp/Pods/FirebaseCore/ shall help, see for example https://github.com/JetBrains/kotlin-native/blob/c7c566ce0f12221088a8908b6dc8e116c56a931b/samples/videoplayer/build.gradle#L15

Trying to use Swift with Obj C header for Coda2 plugin. Getting error: Undefined symbols for architecture x86_64

Trying to build a PlugIn for Coda 2.5 with swift.I'm getting this error:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_CodaPlugInsController", referenced from:
_get_field_types_PowPlugInViewController in PowPlugInViewController.o
_get_field_types_PowPlugIn in PowPlugin.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I have cleaned my build folder.
I have created and added import statements to the project name-bridging-swift.h.
Here is a look at my project.
CodaPlugInsController.h
You can find this file here.
https://github.com/panicinc/CodaPluginKit/tree/master/Cocoa%20Plug-ins
Discription:
This header provides protocols and facilities to implement Coda
text-based, syntax validator and sidebar plug-in.
CodaPow-Bridging-Header.h
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "CodaPlugInsController.h"
PowPlugin.swift
import Foundation
class PowPlugIn: NSObject, CodaPlugIn, CodaSidebarPlugIn {
let PowBundle: CodaPlugInBundle
let PowController: CodaPlugInsController
required init(plugInController: CodaPlugInsController, plugInBundle: CodaPlugInBundle) {
self.PowBundle = plugInBundle
self.PowController = plugInController
super.init()
}
func name() -> String {
return "Coda Pow"
}
func didLoadSiteNamed(name: String!) {
}
func viewController() -> NSViewController {
return PowPlugInViewController(nibName: "PowPlugInView", plugInBundle: PowBundle, plugInController: PowController)!
}
}
PowPlugInViewController.swift
import Foundation
class PowPlugInViewController: NSViewController, CodaSidebarViewController {
let PowController: CodaPlugInsController
init?(nibName: String, plugInBundle: AnyObject, plugInController: CodaPlugInsController) {
self.PowController = plugInController
super.init(nibName: nibName, bundle: plugInBundle as? NSBundle)
}
// Xcode Says I need this.
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I have two more source files.
ServerAndHosts.swift and
Shell.swift They don't use any of the classes in CodaPlugInsController.h. The Shell.swift file is just a set of Class functions.
Edit:
I can use swift as long as I don't subclass from the CodaPlugInsController.h or pass in an object that has been.
Swift and Obj-C versions of Project: https://www.dropbox.com/sh/bsw8cinn7kp9kfe/AAAgG_B44dbHNP5-JwJ3Amf8a?dl=0
The project compiles, so the bridging headers may not be the issue.
You fail at the linking stage, the compiler can't find a set of symbols for your current architecture.
This could either mean
1) The Coda library is not compiled for your architecture
or
2) the linker couldn't find the library at all.
I looked at your Obj-C project, and it appears the Coda library is not in the project, so I'm guessing its #2. You'll either want to move the lib into the project somehow, or add a path to the lib elsewhere on your system in your project's "library search paths"

Unable to link a static C library in an Obj-C project (Xcode 4.6.3)

I'm trying to build a basic FTP client using libftp. I've compiled and archived it as libftp.a and placed it in /usr/local/lib. All the necessary headers I've placed in /usr/local/include/ftp.
Under Build Settings, I've set "Header Search Paths" to /usr/local/include, and I've set "Library Search Paths" to /usr/local/lib. For "Other Linker Flags", I've added -lftp.
Here is the shell of my C++ class:
Connector.h:
#include <stdlib.h>
#include <ftp/ftp.h>
#include <stdio.h>
class Connector{
private:
FtpConnection *connection;
public:
Connector();
~Connector();
bool connect(const char *hostname, const char *port);
};
Connector.cc:
#include "Connector.h"
Connector::Connector(){
}
Connector::~Connector(){
}
bool Connector::connect(const char *hostname, const char *port){
ftpGetAddresses(hostname, port);
printf("Connected!\n");
return true;
}
Upon compiling, this is the error I get:
Undefined symbols for architecture x86_64: "ftpGetAddresses(char
const*, char const*)", referenced from:
Connector::connect(char const*, char const*) in Connector.o ld: symbol(s) not found for architecture x86_64 clang: error: linker
command failed with exit code 1 (use -v to see invocation)
It's probably worth noting that this is part of a Cocoa project, so the Connector class is #included in my AppDelegate, which is of course an Obj-C class. All of my Obj-C source files have the .mm extension.
I am certain that the lib is in working order, as I have no issue compiling a program on the command line with gcc ... -lftp. It's only a problem with Xcode.
Well, it appears I just talked myself through my own problem. As I was typing the last part of my question, I realized that the issue was linking a C library in a C++ source file. gcc would compile just fine on command line, but g++ gave me the same error as Xcode. One google search later I found this link, which solved my problem beautifully. Basically, if you want a C library to be compatible with C++, you need to add
#ifdef __cplusplus
extern "C" {
#endif
at the top of the library header file, and add
#ifdef __cplusplus
}
#endif
at the bottom of the file. I'll leave the question here hoping it will help someone else in the future.