Install
$ agentstack add skill-redth-maui-skillz-android-slim-bindings ✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
When to use this skill
Activate this skill when the user asks:
- How do I create Android bindings for a native library?
- How do I wrap an Android SDK for use in .NET MAUI?
- How do I create slim bindings for Android?
- How do I use Native Library Interop for Android?
- How do I bind a Kotlin library to .NET?
- How do I bind a Java library to .NET?
- How do I integrate an AAR or JAR into .NET MAUI?
- How do I create a Java/Kotlin wrapper for a native Android library?
- How do I update Android bindings when the native SDK changes?
- How do I fix Android binding build errors?
- How do I expose native Android APIs to C#?
- How do I resolve Maven dependencies for Android bindings?
- How do I handle AndroidX dependencies in bindings?
- How do I fix "Java dependency is not satisfied" errors?
- How do I use AndroidMavenLibrary in my binding project?
Overview
This skill guides the creation of Native Library Interop (Slim Bindings) for Android. This modern approach creates a thin native Java/Kotlin wrapper exposing only the APIs you need from a native Android library, making bindings easier to create and maintain.
When to Use Slim Bindings vs Traditional Bindings
| Scenario | Recommended Approach | |----------|---------------------| | Need only a subset of library functionality | Slim Bindings ✓ | | Easier maintenance when SDK updates | Slim Bindings ✓ | | Prefer working in Java/Kotlin for wrapper | Slim Bindings ✓ | | Better isolation from breaking changes | Slim Bindings ✓ | | Complex libraries with many dependencies | Slim Bindings ✓ | | Need entire library API surface | Traditional Bindings | | Creating bindings for third-party developers | Traditional Bindings | | Already maintaining traditional bindings | Traditional Bindings |
Inputs
| Parameter | Required | Example | Notes | |-----------|----------|---------|-------| | libraryName | yes | FirebaseMessaging, OkHttp | Name of the native Android library to bind | | bindingProjectName | yes | MyBinding.Android | Name for the C# binding project | | dependencySource | no | maven, aar, jar | How the native library is distributed | | targetFrameworks | no | net9.0-android | Target frameworks (default: latest .NET Android) | | exposedApis | no | List of specific APIs | Which native APIs to expose (helps scope the wrapper) | | mavenCoordinates | no | com.example:library:1.0.0 | Maven coordinates if library is from Maven repository |
Project Structure
The recommended project structure for Native Library Interop:
MyBinding/
├── android/
│ ├── native/ # Android Studio/Gradle project
│ │ ├── app/
│ │ │ ├── src/main/
│ │ │ │ └── java/com/example/mybinding/
│ │ │ │ └── DotnetMyBinding.java # Java wrapper implementation
│ │ │ │ └── kotlin/com/example/mybinding/
│ │ │ │ └── DotnetMyBinding.kt # Or Kotlin wrapper
│ │ │ └── build.gradle.kts
│ │ ├── settings.gradle.kts
│ │ └── build.gradle.kts
│ └── MyBinding.Android.Binding/
│ ├── MyBinding.Android.Binding.csproj
│ └── Transforms/
│ └── Metadata.xml
├── sample/
│ └── MauiSample/ # Sample MAUI app
│ ├── MauiSample.csproj
│ └── MainPage.xaml.cs
└── README.md
Step-by-step Process
Step 1: Analyze Dependencies First
Before creating any bindings, analyze the complete dependency tree of your target library. This is the most critical step and where most binding projects fail.
Prerequisites
Ensure you have:
- JDK 17+
- Android SDK with
ANDROID_HOMEenvironment variable set - .NET SDK 9+ (recommended for Java Dependency Verification)
> Note: You don't need Gradle installed globally—we'll use the Gradle Wrapper which downloads the correct version automatically.
Step 2: Create the Android Library Project
There are multiple approaches to create the native Android wrapper project. Choose the one that best fits your workflow.
Option A: Use Android Studio (Recommended for GUI)
The most reliable way to create a properly configured Android library:
- Open Android Studio
- File → New → New Project
- Select "No Activity" template
- Configure:
- Name:
MyBindingNative - Package name:
com.example.mybinding - Language: Java or Kotlin
- Minimum SDK: API 21
- File → New → New Module
- Select "Android Library"
- Name it
app(or your preferred module name)
This creates a properly structured project with the latest Gradle plugin versions.
Option B: Use gradle init with Wrapper (CLI)
Use Gradle's built-in initialization to scaffold a project, then convert it to Android:
# Set your binding name
BINDING_NAME="MyBinding"
PACKAGE_NAME="com.example.mybinding"
# Create directory structure
mkdir -p ${BINDING_NAME}/android/native
mkdir -p ${BINDING_NAME}/android/${BINDING_NAME}.Android.Binding/Transforms
mkdir -p ${BINDING_NAME}/sample/MauiSample
cd ${BINDING_NAME}/android/native
# Download and use Gradle wrapper (no global Gradle install needed)
# This downloads gradle-wrapper.jar and creates gradlew scripts
curl -sL https://services.gradle.org/distributions/gradle-9.2.1-bin.zip -o gradle.zip
unzip -q gradle.zip
./gradle-9.2.1/bin/gradle wrapper --gradle-version 9.2.1
rm -rf gradle.zip gradle-9.2.1
# Initialize a basic Kotlin library project
./gradlew init --type kotlin-library --dsl kotlin --project-name ${BINDING_NAME}Native --package ${PACKAGE_NAME} --no-split-project --java-version 17
# The project needs to be converted to Android Library (see next section)
> Note: gradle init creates a standard JVM library, not an Android library. You'll need to modify the generated files to add Android support (see "Converting to Android Library" below).
Option C: Clone from Template Repository
Use the Community Toolkit template as a starting point:
BINDING_NAME="MyBinding"
# Clone the template
git clone https://github.com/AdrianSimionescu/NativeLibraryInterop-Template.git ${BINDING_NAME}
cd ${BINDING_NAME}
# Or use the official CommunityToolkit repo structure
git clone --depth 1 https://github.com/AdrianSimionescu/NativeLibraryInterop-Template.git ${BINDING_NAME}
# Rename files and references
find . -type f -name "*.gradle*" -exec sed -i '' 's/TemplateBinding/'"${BINDING_NAME}"'/g' {} \;
Option D: Manual Creation with Gradle Wrapper
For full control, create the project structure manually but use proper Gradle wrapper initialization:
BINDING_NAME="MyBinding"
PACKAGE_NAME="com.example.mybinding"
PACKAGE_PATH="${PACKAGE_NAME//./\/}"
# Create directory structure
mkdir -p ${BINDING_NAME}/android/native/app/src/main/java/${PACKAGE_PATH}
mkdir -p ${BINDING_NAME}/android/${BINDING_NAME}.Android.Binding/Transforms
mkdir -p ${BINDING_NAME}/sample/MauiSample
cd ${BINDING_NAME}/android/native
# Create Gradle wrapper (downloads correct Gradle version automatically)
# Using gradle wrapper from a temporary init
mkdir -p tmp && cd tmp
curl -sL https://services.gradle.org/distributions/gradle-9.2.1-bin.zip -o gradle.zip
unzip -q gradle.zip && ./gradle-9.2.1/bin/gradle wrapper --gradle-version 9.2.1
mv gradlew gradlew.bat gradle ../ && cd .. && rm -rf tmp
# Now create the project files (see below)
Creating Gradle Build Files
After setting up the wrapper, create the build files. These files define the project structure and can be version-controlled:
settings.gradle.kts:
pluginManagement {
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
mavenCentral()
// Add custom repositories as needed
// maven { url = uri("https://jitpack.io") }
}
}
rootProject.name = "MyBindingNative"
include(":app")
build.gradle.kts (root):
plugins {
// Use version catalog or explicit versions
// Check latest versions at: https://developer.android.com/build/releases/gradle-plugin
id("com.android.library") version "8.2.2" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
}
app/build.gradle.kts:
plugins {
id("com.android.library")
// Include kotlin plugin only if using Kotlin
// id("org.jetbrains.kotlin.android")
}
android {
namespace = "com.example.mybinding"
// Check latest SDK versions: https://developer.android.com/about/versions
compileSdk = 34
defaultConfig {
minSdk = 21
consumerProguardFiles("consumer-rules.pro")
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
// Only needed if using Kotlin
// kotlinOptions {
// jvmTarget = "17"
// }
}
dependencies {
// Add the native library you want to wrap
// implementation("com.squareup.okhttp3:okhttp:4.12.0")
// Common dependencies (only add what you need)
// implementation("androidx.core:core-ktx:1.12.0")
}
Checking for Latest Versions
Always use current versions for Gradle plugins and dependencies:
# Check latest Android Gradle Plugin version
curl -s "https://maven.google.com/web/index.html" | grep -o 'com.android.tools.build:gradle:[0-9.]*' | head -1
# Or check the release notes
open "https://developer.android.com/build/releases/gradle-plugin"
# Check latest Kotlin version
curl -s "https://api.github.com/repos/JetBrains/kotlin/releases/latest" | grep '"tag_name"' | cut -d'"' -f4
Step 3: Analyze the Full Dependency Tree
Add your target library to the dependencies and run:
# Get full dependency tree
./gradlew app:dependencies --configuration releaseRuntimeClasspath
# Get flat list of all dependencies
./gradlew app:dependencies --configuration releaseRuntimeClasspath | grep -E "^[+\\\\]" | sed 's/.*--- //' | sort -u
# For insight into a specific dependency
./gradlew app:dependencyInsight --dependency kotlin-stdlib --configuration releaseRuntimeClasspath
Understanding the output:
->indicates version conflict resolution (e.g.,1.9.10 -> 1.9.21)(*)indicates the dependency was already shown elsewhere (deduplication)(c)indicates a constraint
Document Your Dependencies
Create a dependency mapping document:
| Maven Artifact | Version | NuGet Package | Strategy | |----------------|---------|---------------|----------| | androidx.core:core | 1.12.0 | Xamarin.AndroidX.Core | NuGet | | org.jetbrains.kotlin:kotlin-stdlib | 1.9.22 | Xamarin.Kotlin.StdLib | NuGet | | com.example:internal-lib | 1.0.0 | N/A | Bind="false" | | org.jetbrains:annotations | 23.0.0 | N/A | Ignore |
Step 4: Create the Wrapper Class
Choose Java or Kotlin based on your preference and the native library's language.
Java Wrapper
Create app/src/main/java/com/example/mybinding/DotnetMyBinding.java:
mkdir -p app/src/main/java/com/example/mybinding
cat > app/src/main/java/com/example/mybinding/DotnetMyBinding.java {
try {
Thread.sleep(100); // Simulate network delay
String result = "Result for: " + query;
callback.onSuccess(result);
} catch (Exception e) {
callback.onError(e.getMessage());
}
}).start();
}
/**
* Callback with multiple result types
*/
public interface ComplexCallback {
void onSuccess(String data, int count, boolean hasMore);
void onError(int errorCode, String errorMessage);
}
/**
* Complex async operation with multiple callback parameters
*/
public static void performComplexOperation(
String input,
int options,
final ComplexCallback callback) {
// Perform operation...
callback.onSuccess("data", 42, true);
}
// MARK: - View Creation
/**
* Create a native view to embed in .NET MAUI
* @param context Android context
* @return The native view
*/
public static View createView(Context context) {
// Create and return your native view
// return new TheNativeLibrary.CustomView(context);
View view = new View(context);
view.setBackgroundColor(0xFF0066CC);
return view;
}
// MARK: - Event Handling
/**
* Event listener interface
*/
public interface EventListener {
void onEvent(String eventType, String eventData);
}
private static EventListener eventListener;
/**
* Register an event listener
*/
public static void setEventListener(EventListener listener) {
eventListener = listener;
// Wire up to native library's events
// TheNativeLibrary.setEventHandler(event -> {
// if (eventListener != null) {
// eventListener.onEvent(event.type, event.data);
// }
// });
}
/**
* Remove the event listener
*/
public static void removeEventListener() {
eventListener = null;
}
// MARK: - Configuration
/**
* Set configuration options
* Use simple types that marshal easily
*/
public static void configure(
String apiKey,
String apiSecret,
int timeout,
boolean enableLogging) {
// Apply configuration to native library
Log.d(TAG, "Configured with apiKey: " + apiKey);
}
}
EOF
Kotlin Wrapper (Alternative)
Create app/src/main/kotlin/com/example/mybinding/DotnetMyBinding.kt:
mkdir -p app/src/main/kotlin/com/example/mybinding
cat > app/src/main/kotlin/com/example/mybinding/DotnetMyBinding.kt
net9.0-android
enable
true
21
Update Metadata.xml
Edit the generated Transforms/Metadata.xml to customize the bindings:
MyBinding
context
debug
input
query
callback
Step 7: Resolve Dependencies
This is the critical step. When you build, .NET 9+ will report dependency errors:
cd android/${BINDING_NAME}.Android.Binding
dotnet build
Understanding Dependency Errors
| Error | Meaning | Solution | |-------|---------|----------| | XA4241 | No known NuGet package exists | Use AndroidMavenLibrary with Bind="false" or AndroidIgnoredJavaDependency | | XA4242 | Microsoft maintains a NuGet package | Install the suggested NuGet package |
Dependency Resolution Decision Tree
For each unsatisfied dependency:
│
├─ Is there a XA4242 suggestion?
│ └─ YES → Install the suggested NuGet package
│
├─ Is the dependency needed from C#?
│ ├─ YES → Find/create a binding NuGet or create your own binding
│ └─ NO → Use AndroidMavenLibrary with Bind="false"
│
├─ Is it a compile-time only dependency (annotations, processors)?
│ └─ YES → Use AndroidIgnoredJavaDependency
│
└─ Otherwise → Create a separate binding project or include AAR/JAR directly
Finding NuGet Packages for Maven Dependencies
Microsoft-maintained packages include artifact tags. Search by tag:
# Search NuGet for a specific Maven artifact
dotnet package search "artifact=androidx.core:core" --source https://api.nuget.org/v3/index.json
# Or use curl
curl -s "https://azuresearch-usnc.nuget.org/query?q=tags:artifact=androidx.core:core&take=10" | jq '.data[] | {id: .id, version: .version}'
Common Maven-to-NuGet Mapp
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Redth
- Source: Redth/maui-skillz
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.