Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowThis browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
This article covers how to get started with Native Library Interop using Maui.NativeLibraryInterop to simplify the setup.
These instructions outline the basic steps, key decision points, and guiding examples for creating bindings via Native Library Interop. For further guidance on specific API and implementation details, please refer to documentation for the native SDKs and libraries of interest.
Install prerequisites:
dotnet workload install maui
)xcode-select --install
)Note
It's possible to install the Android SDK and/or the Xcode Command Line Tools in a standalone manner. However, installation of the Xcode Command Line Tools is typically handled via Xcode. Likewise, Android SDK installation is also typically handled via Android Studio and/or the .NET MAUI VS Code Extension as-per the .NET MAUI Getting Started documentation.
The easiest way to get started with creating a new binding is by cloning the template in the Maui.NativeLibraryInterop repo and making modifications from there. To better understand the full scope of how Maui.NativeLibraryInterop is currently set up, read more in the overview documentation.
The template includes starter .NET for Android and .NET for iOS binding libraries.
Update the binding libraries to reflect the target platforms and .NET version as needed in your .NET app.
Note
For example: If you aim to create only an iOS binding using .NET 9, you can:
net9.0-ios
.The template also includes starter Android Studio projects and Xcode projects.
Update the native projects to reflect the target platforms and versions as needed in your .NET app, and include the native libraries of interest with the following steps.
The Xcode project is located at template/macios/native/NewBinding.
Update the Xcode project to reflect the target platforms and versions as supported in your .NET app. In the Xcode project, click on the top-level framework, and in Targets > General:
Bring in the native library for iOS and/or MacCatalyst into your Xcode project, through whatever method works best for your library and your needs (e.g., CocoaPods, Swift Package Manager).
The Android Studio project is located at template/android/native.
Update the Android Studio project to reflect the target versions supported in your .NET app.
compileSdk
version as neededBring in the Android native library through gradle
dependencyResolutionManagement
repositories
block in the settings.gradle.kts file.Create the API interface between your native projects and your .NET binding projects with the following steps.
On the native side, make updates in template/macios/native/NewBinding/NewBinding/DotnetNewBinding.swift:
Back on the .NET side, we are now ready to interop with the native library:
dotnet build
from template/macios/NewBinding.MaciOS.Binding to test everything is plugged in correctly and good to go.sharpie xcode -sdks
to get a list of valid target SDK values for the bind command. Select the value that aligns with the platform and version you are targeting to use with the next command, for example iphoneos18.0
.sharpie bind
against the header files in the xcframework created by the binding project:
sharpie bind --output=sharpie-out --namespace=NewBindingMaciOS --sdk=iphoneos18.0 --scope=Headers Headers/NewBinding-Swift.h
dotnet build
from template/macios/NewBinding.MaciOS.Binding again.See also the objective-sharpie documentation to learn more about this tool.
On the native side, make updates in template/android/native/newbinding/src/main/java/com/example/newbinding/DotnetNewBinding.java:
Back on the .NET side, we are now ready to interop with the native library:
dotnet build
from template/android/NewBinding.Android.Binding to test everything is plugged in correctly and good to go. (Note: This step will require that you have JDK 17 installed)@(AndroidMavenLibrary)
item to template/sample/MauiSample.csproj for each maven dependency being bound in your native Android project. This will enable Java dependency verification for your project and cause subsequent builds to produce build warnings or errors for missing dependencies. You can address these warnings/errors by adding @(AndroidMavenLibrary)
or @(PackageReference)
elements as suggested to satisfy the java dependency chain for the native library you are binding. (Note: The gradle/maven dependencies often need to be explicitly referenced, as they are not automatically bundled into your library.)<ItemGroup Condition="$(TargetFramework.Contains('android'))">
<AndroidMavenLibrary Include="{DependencyGroupId}:{DependencyName}" Version="{DependencyVersion}" Bind="false" />
</ItemGroup>
See also the AndroidMavenLibrary reference and Java dependency verification documentation for more information about this process.
Note
You can rename the placeholder DotnetNewBinding
class to better reflect the native library being wrapped. For more examples and tips for writing the API definitions, read more in the section below: Modify an existing binding.
The template includes a .NET MAUI sample app at template/sample/MauiSample, which references the .NET binding projects and makes the native libraries immediately ready to use!
If you are interested in using your own .NET MAUI, .NET for Android, .NET for iOS, and/or .NET for Mac Catalyst apps, however, you may do so by modifying your .NET app project files to reference the binding libraries:
<!-- Reference to MaciOS Binding project -->
<ItemGroup Condition="$(TargetFramework.Contains('ios')) Or $(TargetFramework.Contains('maccatalyst'))">
<ProjectReference Include="..\..\macios\NewBinding.MaciOS.Binding\NewBinding.MaciOS.Binding.csproj" />
</ItemGroup>
<!-- Reference to Android Binding project -->
<ItemGroup Condition="$(TargetFramework.Contains('android'))">
<ProjectReference Include="..\..\android\NewBinding.Android.Binding\NewBinding.Android.Binding.csproj" />
</ItemGroup>
If the existing API surface doesn't expose the functionality you need in your own project, it's time to make your own modifications!
Inside the Xcode project, you will find one or more Swift files which define the public API surface for the binding. For example, the register
method for Firebase Messaging is defined as:
@objc(MauiFIRMessaging)
public class MauiFIRMessaging : NSObject {
@objc(register:completion:)
public static func register(apnsToken: NSData, completion: @escaping (String?, NSError?) -> Void) {
let data = Data(referencing: apnsToken);
Messaging.messaging().apnsToken = data
Messaging.messaging().token(completion: { fid, error in
completion(fid, error as NSError?)
})
}
// ...
}
Note
Native wrapper API types which will be used by the .NET Binding must be declared as public
and need to be annoted with @objc(NameOfType)
and methods also need to be public
, and can also benefit from similar annotations @objc(methodName:parameter1:)
where the name and parameters are specified which help influence the binding which objective sharpie will generate.
You can see in this method that the public API surface only uses types which .NET for iOS is already aware of: NSData
, String
, NSError
and a callback.
In the Firebase.MaciOS.Binding
project, the ApiDefinitions.cs file contains the binding definition for this native wrapper API:
using System;
using Foundation;
namespace Firebase
{
// @interface MauiFIRMessaging : NSObject
[BaseType (typeof(NSObject))]
interface MauiFIRMessaging
{
[Static]
[Export ("register:completion:")]
[Async]
void Register (NSData apnsToken, Action<string?, NSError?> completion);
// ...
}
Let's say you want to add a method for unregistering. The Swift code would look something like this:
@objc(unregister:)
public static func unregister(completion: @escaping (NSError?) -> Void) {
// need delegate to watch for fcmToken updates
Messaging.messaging().deleteToken(completion: { error in
completion(error as NSError?)
})
}
The other half will be to update the ApiDefinitions.cs file in the binding project to expose this new method. There are two ways you can go about this:
In this case, the changes to ApiDefinitions.cs would be:
[Static]
[Export("unregister:")]
[Async]
void UnRegister(Action completion);
Once you've made these changes, you can rebuild the Binding project, and the new API will be ready to use from your .NET MAUI project.
Note
Binding projects for Mac/iOS are not using source generators, and so the project system and intellisense may not know about the new API's until you've rebuilt the binding project, and reloaded the solution so that the project reference picks up the newer assembly. Your app project should still compile regardless of intellisense errors.
Inside the Android Studio project you will find a module directory which contains a java file definining the public API surface for the binding. For example, the initialize
method for Facebook is defined as below:
package com.microsoft.mauifacebook;
import android.app.Activity;
import android.app.Application;
import android.os.Bundle;
import android.util.Log;
import com.facebook.LoggingBehavior;
import com.facebook.appevents.AppEventsLogger;
public class FacebookSdk {
static AppEventsLogger _logger;
public static void initialize(Activity activity, Boolean isDebug) {
Application application = activity.getApplication();
if (isDebug) {
com.facebook.FacebookSdk.setIsDebugEnabled(true);
}
com.facebook.FacebookSdk.addLoggingBehavior(LoggingBehavior.APP_EVENTS);
AppEventsLogger.activateApp(application);
_logger = AppEventsLogger.newLogger(activity);
}
// ...
}
You can see in this method that the public API surface only uses types which .NET for Android is already aware of: Activity
and Boolean
.
In the Facebook.Android.Binding project, the Transforms/Metadata.xml file contains only some xml to describe how to map the java package name (com.microsoft.mauifacebook
) to a more C# friendly namespace (Facebook
). Generally android bindings are more 'automatic' than Mac/iOS at this point, and you rarely should need to make changes to these transform files.
<metadata>
<attr path="/api/package[@name='com.microsoft.mauifacebook']" name="managedName">Facebook</attr>
</metadata>
Let's say you want to add a method for logging an event. The java code would look something like this:
public static void logEvent(String eventName) {
_logger.logEvent(eventName);
}
From this simple change, binding project requires no updates to the Transforms/Metadata.xml or other files. You can simply rebuild the Binding project, and the new API will be ready to use from your .NET MAUI project.
Note
Binding projects for Android are not using source generators, and so the project system and intellisense may not know about the new API's until you've rebuilt the binding project, and reloaded the solution so that the project reference picks up the newer assembly. Your app project should still compile regardless of intellisense errors.
.NET MAUI Community Toolkit feedback
.NET MAUI Community Toolkit is an open source project. Select a link to provide feedback:
Events
Mar 17, 9 PM - Mar 21, 10 AM
Join the meetup series to build scalable AI solutions based on real-world use cases with fellow developers and experts.
Register nowTraining
Module
Create a UI that uses data binding in .NET MAUI. - Training
Create a UI with data binding. Your UI automatically updates based on the latest data, while the data updates in response to changes in the UI.
Documentation
Native Library Interop - .NET MAUI Community Toolkit - Community Toolkits for .NET
The .NET MAUI Community Toolkit Native Library Interop components
Binding Native Libraries for .NET MAUI
NET MAUI is a solution for developing cross-platform applications. On iOS/Android systems, there are many native libraries, including maps, cameras, communities, etc. We usually combine these native libraries to build applications. This course will introduce how to bind with native libraries in the .NET MAUI, allowing developers to combine third-party libraries to create the best .NET MAUI cross-platform applications. Connect Kinfey Lo on Twitter!
Binding and Using Native Libraries in .NET MAUI
Rachel joins James to show of some new features to creating binding around native libraries for .NET MAUI apps. Rachel walks through Native Library Interop for .NET MAUI which greatly simplifies the binding process and some new templates to get your started. Chapters 00:00 - Intro 01:00 - What is a Binding? 02:30 - What is Native Library Interop? 05:00 - How Native Library Interop Works 08:00 - Create your first binding with Native Library Interop Template 13:30 - Binding a native chart library for iOS and