We have already introduced how to bind the iOS native library through .NET, and this article will introduce how to bind the Android native library through .NET.
Libraries for Android
The Android library is packaged in .jar. With tools, you can bind multiple .jars, and then call the native Java library through C#. Compared to iOS, Android's library bindings are much simpler.
As you can see from the image above, Xamarin.Android / .NET for Android implements bindings by using a Managed Callable Wrapper (MCW). MCW is a JNI bridge that is used when managed code needs to call Java code. Managed callable wrappers also support subclassing Java types and overriding virtual methods of Java types. Likewise, whenever Android Runtime (ART) code needs to call managed code, it does so through another JNI bridge called the Android Callable Wrapper (ACW).
Create an Android native library binding project
Create an Android native library binding project through the command line d
otnet new android-bindinglib -o Droid.AMap
Enter the project and let's take a look at the file structure
There are three corresponding xml files in the Transforms folder in the project, namely EnumFields.xml , EnumMethods.xml , Metadata.xml , and their functions are as follows:
- MetaData.xml - Allows changes to the final API, such as changing the namespace of the generated bindings.
- EnumFields.xml – Contains mappings between Java int constants and C# enums.
- EnumMethods.xml - allows changing method parameters and return types from Java int constants to C# enums
The MetaData.xml file is the most common import of these files, as it allows general-purpose changes to bindings, such as renaming a namespace, class, method, or field so that it Follow .NET conventions.
Delete unneeded namespaces, classes, methods or fields.
Move classes to different namespaces.
Add additional support classes to make the design of the binding follow the .NET Framework pattern.
▌Add the jar file to the binding project
Add the Jars directory to the project, add the jar package of AutoNavi to this directory, and add the three directories arm64-v8a, armeabi-v7a, x86_64 to it
After adding, modify the .csproj file
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-android</TargetFramework>
<SupportedOSPlatformVersion>21</SupportedOSPlatformVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<EmbeddedNativeLibrary Include="Jars\arm64-
v8a\libAMapSDK_MAP_v9_3_0.so" />
<EmbeddedNativeLibrary Include="Jars\armeabiv7a\libAMapSDK_MAP_v9_3_0.so" />
<EmbeddedNativeLibrary Include="Jars\x86_64\libAMapSDK_MAP_v9_3_0.so"
/>
</ItemGroup>
<ItemGroup>
<TransformFile Include="Transforms\Metadata.xml" />
<TransformFile Include="Transforms\EnumFields.xml" />
<TransformFile Include="Transforms\EnumMethods.xml" />
</ItemGroup>
<ItemGroup>
<EmbeddedJar
Include="Jars\AMap3DMap_9.3.0_AMapSearch_9.2.0_AMapLocation_6.1.0_20220608
.jar" />
</ItemGroup>
</Project>
In this way, the project is added, and it is not as cumbersome as the iOS native library binding. Then compile it, Versailles + Sea of Stars
Demining work
Seeing so many mistakes, we really need to consider whether to give up. In fact, this is also very healing. We will clear mines one by one.
- 'PoiCreator' does not implement interface member 'IParcelableCreator.NewArray(int)'.
- 'PoiCreator.NewArray(int)' cannot implement 'IParcelableCreator.NewArray(int)'
The error corresponds to this method. In fact, the return type is wrong. We can solve it by looking at the path according to the source file.
// Metadata.xml XPath method reference:
path="/api/package[@name='com.amap.api.maps.model']/class[@name='PoiCreato
r']/method[@name='newArray' and count(parameter)=1 and parameter[1]
[@type='int']]"
[Register ("newArray", "(I)[Lcom/amap/api/maps/model/Poi;",
"GetNewArray_IHandler")]
public virtual unsafe global::Com.Amap.Api.Maps.Model.Poi[]? NewArray (int
p0)
{
const string __id = "newArray.(I)[Lcom/amap/api/maps/model/Poi;";
try {
JniArgumentValue* __args = stackalloc JniArgumentValue [1];
__args [0] = new JniArgumentValue (p0);
var __rm = _members.InstanceMethods.InvokeVirtualObjectMethod
(__id, this, __args);
return (global::Com.Amap.Api.Maps.Model.Poi[]?)
JNIEnv.GetArray (__rm.Handle, JniHandleOwnership.TransferLocalRef, typeof
(global::Com.Amap.Api.Maps.Model.Poi));
} finally {
}
}
After confirmation, you need to add it in Metadata.xml
<attr
path="/api/package[@name='com.amap.api.maps.model']/class[@name='PoiCreato
r']/method[@name='newArray' and count(parameter)=1 and parameter[1]
[@type='int']]" name="managedReturn">Java.Lang.Object[]</attr>
- The type 'AMap' already contains a definition for 'MarkerDragEnd'
This is caused by repeated definitions, just add the following code to delete, such as
<remove-node
path="/api/package[@name='com.amap.api.maps']/interface[@name='AMap.OnCame
raChangeListener']" />
- 'BusLineSearch': member names cannot be the same as their enclosing type
For errors caused by renaming, just change the name, such as
<attr
path="/api/package[@name='com.amap.api.services.busline']/class[@name='Bus
LineSearch']" name="managedName">AmapBusLineSearch</attr>
- cannot change access modifiers when overriding 'protected'
There is a permission problem when reloading. At this time, you need to correct the permissions, such as
<attr
path="/api/package[@name='com.amap.api.maps.model']/class[@name='PolygonOp
tions']/method[@name='getUpdateFlags' and count(parameter)=0]"
name="visibility">protected</attr>
Solve all the above problems, basically it can be cured, you will be very excited when the compilation passes
Find a .NET for Android project to see
Android's native binding is much simpler than iOS's, so it's easier to get started. I hope all of you can be more active, sometimes it is a good experience. After learning, I believe that everyone has mastered how to use .NET to bind the native libraries of iOS and Android.
We know that MAUI is a solution for developing cross-platform applications, and applications such as iOS, Android, Windows, macOS, Linux, Tizen, etc. can be developed directly with C#. Then, in addition to using the underlying custom UI controls in this framework, what should we do if we want to use third-party controls such as AutoNavi Maps? Next, I will introduce it to you.
If you haven't learned the knowledge of native library binding, you can go to the following links to learn related content:
- About making an iOS / Android MAUI control for AutoNavi map (iOS native library binding)
- Make an iOS / Android MAUI control for AutoNavi map (Android native library binding)
In the above two examples, we learned to bind the native AutoNavi iOS / Android SDK, and also used .NET for iOS and .NET for Android to call. But using MAUI means changing the calling method, writing one-time multi-platform use. To achieve this effect, first look at the MAUI infrastructure.
We can clearly see that in addition to the public xmal file, MAUI actually puts some platform-specific settings into the Platforms folder, and the Platforms self-folder is the corresponding platform. We know that the platform interface can be rendered according to different platforms. This is what we often call custom platform controls.
In the previous part, we also mentioned that MAUI uses the Handler mode to set the platform interface. If we want to implement a MAUI control of AutoNavi map, the specific architecture is like this
We need to create a structure as shown above, we need to add a shared file AMap.shared.cs for AMap, this file AMapHandler succeeds ViewHandler.
public interface IAMap : IView
{
}
public class AMap : View, IAMap
{
}
partial class AMapHandler
{
public static IPropertyMapper<AMap, AMapHandler> MapMapper = new
PropertyMapper<AMap, AMapHandler>(ViewHandler.ViewMapper)
{ };
public AMapHandler() : base(MapMapper)
{ }
}
Then add the respective platform AMap calling methods in the Android and iOS folders under Platforms.
Add the rendering method of AutoNavi map in Android environment to AMap.Android.cs
namespace AMap.UI.Apps
{
public partial class AMapHandler : ViewHandler<IAMap, MapView>
{
private AMapHelper _mapHelper;
private MapView mapView;
internal static Bundle Bundle { get; set; }
public AMapHandler(IPropertyMapper mapper, CommandMapper
commandMapper = null) : base(mapper, commandMapper)
{
}
protected override MapView CreatePlatformView()
{
mapView = new Com.Amap.Api.Maps.MapView(Context);
03.UIControls.md 7/5/2022
4 / 8
return mapView;
}
protected override void ConnectHandler(MapView platformView)
{
base.ConnectHandler(platformView);
AMapLocationClient.UpdatePrivacyAgree(Context, true);
AMapLocationClient.UpdatePrivacyShow(Context, true, true);
_mapHelper = new AMapHelper(Bundle, platformView);
mapView = _mapHelper.CallCreateMap();
}
}
class AMapHelper : Java.Lang.Object
{
private Bundle _bundle;
private MapView _mapView;
public event EventHandler MapIsReady;
public MapView Map { get; set; }
public AMapHelper(Bundle bundle, MapView mapView)
{
_bundle = bundle;
_mapView = mapView;
}
public MapView CallCreateMap()
{
_mapView.OnCreate(_bundle);
return _mapView;
}
}
}
Add the rendering method of AutoNavi map in iOS environment to AMap.iOS.cs
namespace AMap.UI.Apps
{
public partial class AMapHandler : ViewHandler<IAMap, MAMapView>
{
public AMapHandler(IPropertyMapper mapper, CommandMapper
commandMapper = null) : base(mapper, commandMapper)
{
}
protected override MAMapView CreatePlatformView()
{
MAMapView.UpdatePrivacyShow(AMapPrivacyShowStatus.DidShow,
AMapPrivacyInfoStatus.DidContain);
MAMapView.UpdatePrivacyAgree(AMapPrivacyAgreeStatus.DidAgree);
AMapServices.SharedServices.ApiKey = "";
AMapServices.SharedServices.EnableHTTPS = true;
//try
//{
MAMapView map = new MAMapView();
map.SetShowsUserLocation(true);
map.SetUserTrackingMode(MAUserTrackingMode.Follow);
return map;
}
protected override void ConnectHandler(MAMapView PlatformView)
{ }
protected override void DisconnectHandler(MAMapView PlatformView)
{
if (PlatformView.Delegate != null)
{
PlatformView.Delegate.Dispose();
PlatformView.Delegate = null;
}
PlatformView.RemoveFromSuperview();
}
}
}
Here we are going to modify the MAUI project file. There are several settings that need to be paid attention to.
- Because this control is only for iOS/Android two platforms, so we only keep net6.0-android and net6.0-ios
- It is recommended to use the AutoNavi SDK to run on a real machine, especially iOS, you need to specify a version number and a compilation environment. My environment is under Apple silicon, so I also need to set the RuntimeIdentifier, and when compiling, I spent a lot of time here, you can refer to this issue of my self-answer on GitHub
https://github.com/xamarin/xamarin-macios/issues/15372
<PropertyGroup Condition="$(TargetFramework.Contains('-ios'))">
<RuntimeIdentifier>ios-arm64</RuntimeIdentifier>
<UseMSBuildEngine>true</UseMSBuildEngine>
<WarningLevel>4</WarningLevel>
<MtouchLink>SdkOnly</MtouchLink>
<SupportedOSPlatformVersion>13.0</SupportedOSPlatformVersion>
<DeviceSpecificBuild>true</DeviceSpecificBuild>
<MtouchDebug>true</MtouchDebug>
<MtouchFastDev>true</MtouchFastDev>
<MtouchProfiling>true</MtouchProfiling>
<MtouchUseSGen>true</MtouchUseSGen>
<MtouchUseRefCounting>true</MtouchUseRefCounting>
<MtouchFloat32>true</MtouchFloat32>
</PropertyGroup>
3. Remember to introduce the binding of the native library according to the platform
<ItemGroup Condition=" '$(TargetPlatformIdentifier)' == 'ios' ">
<ProjectReference
Include="..\iOS.AmapSDK.Foundation\iOS.AmapSDK.Foundation.csproj" />
<ProjectReference Include="..\iOS.AmapSDK.3D\iOS.AmapSDK.3D.csproj" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetPlatformIdentifier)' == 'android' ">
<ProjectReference Include="..\Droid.AmapSDK\Droid.AmapSDK.csproj" />
</ItemGroup>
- To view the full project file, please click this link
- Don't forget to set some platform-specific settings. For details, please click this link for iOS settings.
- For Android settings please click this link
The last step is to register on MauiProgram.cs
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
})
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(AMap), typeof(AMapHandler));
});
Choose to compile and run to see that the AutoNavi map can finally run in the MAUI environment
summary
For many people, or they have just come into contact with MAUI, in fact, there is still a long way to go to be compatible with many platforms. I hope that through this series of articles, I can give some help to some third-party manufacturers and developers, and provide MAUI support as soon as possible. Only in this way can this new technology be injected with vitality.
Relevant information:
- .Understanding MAUI with Microsoft Docs
- Learn MAUI with Microsoft Learn
- To use AutoNavi Map SDK for Android, please visit
- To understand the content of the Android native library binding, please visit
- To learn ViewHandler custom MAUI components, please click to visit this link
Long press to identify the QR code and follow Microsoft China MSDN
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。