简体   繁体   中英

Is it possible to use business code for Android and iOS written in Kotlin in a multiplatform Xamarin application?

I have some code that is written in Java and Kotlin for Android; the Java part can be translated into Kotlin using the Android Studio. Most of this code is business; that means, independent on any hardware or platform specifics; some Android specific classes (like "Bitmap") can be replaced by abstract or general self-defined classes.

As already known, Kotlin business code can be used in multiplatform applications for Android and iOS. Description here: https://kotlinlang.org/docs/multiplatform-mobile-integrate-in-existing-app.html . Xamarin is used for multiplatform apps, too.

On the other hand, there is a way to include Kotlin code in Xamarin projects. For this purpose, the Xamarin.Kotlin.StdLib is used: https://libraries.io/nuget/Xamarin.Kotlin.StdLib .

My question: Is it possible to develop a Xamarin project (maybe with Xamarin Forms) that includes the Kotlin business code and will work in both Android and iOS environments?

我在另一个论坛上发布了同样的问题 - https://docs.microsoft.com/en-us/answers/questions/875957/use-business-code-for-android-and-ios-written-in-k。 html - 我已经发布了一个可能的答案,请参阅 2022 年 7 月 19 日的答案。剧透:是的,有可能,但不是直接的,而且很复杂。

Here are some instructions.

  1. ANDROID STUDIO
  • Create a new Project: "File -> New -> New Module -> Kotlin
    Multiplatform Shared Module".
  • Follow these instructions:
    https://kotlinlang.org/docs/multiplatform-mobile-integrate-in-existing-app.html until "Run your cross-platform application on Android".
  • For Android we're finished. Following steps are only for iOS.
  • We now assume that there is a module with the name "shared". If this module has another name, please replace it in the following instructions.
  1. XCODE:

The following instructions are similar to that in https://kotlinlang.org/docs/multiplatform-mobile-integrate-in-existing-app.html#make-your-cross-platform-application-work-on-ios . The difference is that we don't want to build the app now, but a framework.

  • File New - Project.

  • Select the template for "Framework" and click "Next".

  • Choose a product name (for example, "KmmExample"). Language: Objective C

  • Build Phases - New Run Script Phase:

     cd "$SRCROOT/.." chmod +x gradlew./gradlew:shared:embedAndSignAppleFrameworkForXcode
  • Move the Run Script phase up so that it is located after the "Dependencies" item.

  • On the Build Settings tab, switch to "All" build settings.

  • In the Search Paths paragraph, specify the Framework Search Path for both Debug and Release:

     $(SRCROOT)/../shared/build/xcode-frameworks/$(CONFIGURATION)/$(SDK_NAME)
  • In the Linking paragraph:

  • Specify the "Mach-O Type" as "Static Library".

  • Specify the Other Linker Flags as

     $(inherited) -framework shared
  • In the Architectures paragraph, "Architectures" may be unchanged or changed to "$(ARCHS_STANDARD_INCLUDING_64_BIT)".

  • Build the project.

  • If successful, there will be a folder structure inside "shared/build". There will be a subfolder "xcode-frameworks". In the "Debug" resp. "Release" directory, there will be subfolder(s) with the name(s) of the iOS device(s) or simulator(s). For example, "iphonesimulator15.5". It contains another subfolder: "shared.framework". In the "Headers" you find a "shared.h", and there is the library itself: "shared". (In the "shared/build" folder there will be also a "bin" directory with device and simulator names containing "debugFramework" and similar structures inside.)

  1. OBJECTIVE SHARPIE

Type:

sharpie bind --output=./SharpieOutput --namespace=Shared --sdk iphoseos15.5 -scope./shared./shared/build/xcode-frameworks/Debug/iphonesimulator15.5/shared.framework/Headers/shared.h

(please replace "iphoneos15.5" by the correct SDK and "Debug/iphonesimulator15.5" by the correct folder name) You also can choose another namespace instead of "Shared". It will be specified in the ApiDefinitions.h.

  • If successful, a "ApiDefinitions.cs" will be in a new subfolder "SharpieOutput".
  1. VISUAL STUDIO / XAMARIN

Use Visual Studio 2019 or 2022 or higher.

  • Create a new Solution, say, "MyApp".
  • "MyApp" should contain four projects: "MyApp", "MyApp.Android", "MyApp.iOS".
  • Here, we don't talk about "MyApp.Android".
  • Right-click on the solution name and add a "New Project". Choose "iOS - Library - Bindings Library". Its name may be "MyApp.iOS.Binding".
  • Replace the ApiDefinitions.cs by that that has been created in the precding step.
  • Add the "shared" library (created by XCode in one of the steps above) as a "Native Library".
  • Right-click on ApiDefinitions.cs and change "Build action" = "ObjcBindingApiDefinition".
  • When you now open ApiDefinitions.cs, you'll probably see a lot of errors and marked lines. They may be handled as follows:
  • For the "[Verify]" attribute, please check here: https://docs.microsoft.com/en-us/xamarin/ios/platform/binding-swift/walkthrough#build-a-binding-library , section 5.
  • If "NativeHandle" creates a compiler error, please add at the top:
 #if.NET using NativeHandle=System;IntPtr; #endif
  • You may remove "using" with the shared module ("using shared")

  • If you encounter errors like "Cannot declare instance members in a static class (CS0708) and "static classes cannot implement interfaces" (CS0714): try to comment out or remove the attribute "[Category]".

  • "[Unavailable (PlatformName.Swift)]" may be removed if yielding an error.

  • Handle typed classes resp. Interfaces with "<T>". For example, the "<T>" attribute should be added to some interfaces representing typed classes. In some cases special handling is necessary.

  • CS0246: In some cases, when an element cannot be found, an attribute "[BaseType(typeof(SharedBase))]" may help (assuming that the interface SharedBase is defined at the beginning of this file).

  • If, during a build run, there are warnings CS8767 ("… hides inherited member"), add the attribute [Override] above these members. For "New()", however, add "[New]" instead.

  • In case of linker errors MT5211 "Native linking failed, undefined Objective-C class …", add the attribute " [Protocol] " in front of the interface definition:

     [BaseTye (typeof (NSObject))] [Protocol] public interface MyInterface { … }
  • Other compiler / linker errors (eg " … was built for newer iOS version (…) than being linked …" possibly can result in warnings after that.

  • The "MyApp" project contains all platform independent code. Those classes which contain platform dependent parts should be defined as interfaces.

  • "MyApp.Android" and "MyApp.iOS" should implement these interfaces. For "MyApp.iOS", "MyApp" and "MyApp.iOS.Binding" should be added as References. The classes implementing those interfaces now can use the interfaces defined in ApiDefinitions.h.

End of instructions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM