【问题标题】:Xamarin.iOS Binding Libraries / Native FrameworksXamarin.iOS 绑定库/本机框架
【发布时间】:2017-03-22 21:25:54
【问题描述】:

由于某种原因,我需要在我的 Xamarin.iOS 应用程序中使用 this 本机框架,但问题来了,我不知道如何正确进行绑定.


所以我理解正确,这个框架还使用了另一个framework,我有点困惑,我到底需要做什么?


问题:

  1. 我是否需要像official documentation of Xamarin 上显示的那样实现静态库(这可能与 本机框架 相关)?
  2. 我可以make bindings for native framework 使用另一个框架还是我需要单独实现它们?
  3. 也许我应该将所有这些原生框架重写为 C# 版本?!? (但这里出现了另一个问题,框架使用 ObjC 并且对我来说很难在 C# 中重现)李>
  4. 实现我的目标的最佳方法是什么?(可能没有描述,您可以告诉我更多信息)。

有什么建议吗?谢谢!

【问题讨论】:

    标签: ios xamarin.ios static-libraries ios-frameworks xamarin.ios-binding


    【解决方案1】:

    好的,我终于制作了一个静态库,但是出了点问题,目前我无法在Emulator上使用它。 :(

    我将逐步解释我是如何制作静态库的:

    • 我从这个repository 获得了所有源文件。
    • Xcode IDE 中,我制作了 Static Library 项目,之后我从存储库到我的项目。

    • 通过 Carthage 我已经下载了this framework(正如我所解释的,源文件使用这个框架)并且我在 Build Phases 中添加了新类别 -> 复制文件(我选择了框架)到我的 Static Library 中。并成功构建(在部署目标 10.2)

      .

    • 接下来,我制作了 MakeFile 并成功生成了四个 Fat Binary .a 库任何问题。

    Xcrun 命令显示:

     xcrun -sdk iphoneos lipo -info libOSMapKitAdapter.a
     Architectures in the fat file: libOSMapKitAdapter.a are: i386 armv7 x86_64 arm64
    
    • 然后我在 Xamarin 中创建了 Binding Library 项目,并将 Fat Binary Static Library 添加为 Native Reference(我将在下面显示我的 .csproj 文件)并且我已经为链接在 静态库(可能是多余的?)


      此外,我还制作了名为 OSTransformation.framework.linkwith.cs 的附加文件,其代码为:

    • 通过 Objective Sharpie 我已生成 ApiDefinition.csStructs.cs。 命令:

      sharpie bind --output=OSMapKitAdapter --namespace=OSMapKitAdapter --sdk=iphoneos10.2 /MyPath/OSMapKitAdapter/OSMapKitAdapter/*.h

    结果是:

    Parsing 5 header files...
    
    Binding...
      [write] ApiDefinitions.cs
      [write] StructsAndEnums.cs
    
    Binding Analysis:
      Automated binding is complete, but there are a few APIs which have been flagged with [
      Verify] attributes. While the entire binding should be audited for best API design
      practices, look more closely at APIs with the following Verify attribute hints:
    
      ConstantsInterfaceAssociation (1 instance):
        There's no foolproof way to determine with which Objective-C interface an extern
        variable declaration may be associated. Instances of these are bound as [Field]
        properties in a partial interface into a nearby concrete interface to produce a more
        intuitive API, possibly eliminating the 'Constants' interface altogether.
    
      PlatformInvoke (4 instances):
        In general P/Invoke bindings are not as correct or complete as Objective-C bindings (
        at least currently). You may need to fix up the library name (it defaults to '__
        Internal') and return/parameter types manually to conform to C calling conventionsfor
        the target platform. You may find you don't even want to expose the C API in your
        binding, but if you do, you'll probably also want to relocate the definition to a
        more appropriate class and expose a stronger type-safe wrapper. For P/Invoke guidance,
         see http://www.mono-project.com/docs/advanced/pinvoke/.
    
      Once you have verified a Verify attribute, you should remove it from the binding source
      code. The presence of Verify attributes intentionally cause build failures.
    
      For more information about the Verify attribute hints above, consult the Objective
      Sharpie documentation by running 'sharpie docs' or visiting the following URL:
    
        http://xmn.io/sharpie-docs
    
    Submitting usage data to Xamarin...
      Submitted - thank you for helping to improve Objective Sharpie!
    
    Done.
    

    ApiDefinition.cs的生成代码如下:

    [Static]
        [Verify (ConstantsInterfaceAssociation)]
        partial interface Constants
        {
            // extern double OSMapKitAdapterVersionNumber;
            [Field ("OSMapKitAdapterVersionNumber", "__Internal")]
            double OSMapKitAdapterVersionNumber { get; }
    
            // extern const unsigned char [] OSMapKitAdapterVersionString;
            [Field ("OSMapKitAdapterVersionString", "__Internal")]
            byte[] OSMapKitAdapterVersionString { get; }
        }
    
        // @interface OSTileOverlay : MKTileOverlay
        [BaseType (typeof(MKTileOverlay))]
        interface OSTileOverlay
        {
            // @property (assign, nonatomic) BOOL clipOverlay;
            [Export ("clipOverlay")]
            bool ClipOverlay { get; set; }
    
            // -(instancetype _Nonnull)initWithAPIKey:(NSString * _Nonnull)apiKey product:(OSMapProduct)product __attribute__((objc_designated_initializer));
            [Export ("initWithAPIKey:product:")]
            [DesignatedInitializer]
            IntPtr Constructor (string apiKey, OSMapProduct product);
        }
    
        // @interface OSMapViewRegionRestriction : NSObject
        [BaseType (typeof(NSObject))]
        interface OSMapViewRegionRestriction
        {
            // @property (readonly, nonatomic) MKCoordinateRegion initialRegion;
            [Export ("initialRegion")]
            MKCoordinateRegion InitialRegion { get; }
    
            // -(void)updateMapViewRegionIfRequired:(MKMapView * _Nonnull)mapView;
            [Export ("updateMapViewRegionIfRequired:")]
            void UpdateMapViewRegionIfRequired (MKMapView mapView);
        }
    
        // @interface OSMapKitAdapter : NSObject
        [BaseType (typeof(NSObject))]
        interface OSMapKitAdapter
        {
        }
    

    Structs.cs

    [Native]
    public enum OSMapProduct : nint
    {
        Road,
        Outdoor,
        Light,
        Night
    }
    
    static class CFunctions
    {
        // extern NSString * NSStringFromOSMapProduct (OSMapProduct product);
        [DllImport ("__Internal")]
        [Verify (PlatformInvoke)]
        static extern NSString NSStringFromOSMapProduct (OSMapProduct product);
    
        // extern CLLocationCoordinate2D OSUpperLeftCorner ();
        [DllImport ("__Internal")]
        [Verify (PlatformInvoke)]
        static extern CLLocationCoordinate2D OSUpperLeftCorner ();
    
        // extern CLLocationCoordinate2D OSLowerRightCorner ();
        [DllImport ("__Internal")]
        [Verify (PlatformInvoke)]
        static extern CLLocationCoordinate2D OSLowerRightCorner ();
    
        // extern MKMapRect OSMapRectForUK ();
        [DllImport ("__Internal")]
        [Verify (PlatformInvoke)]
        static extern MKMapRect OSMapRectForUK ();
    }
    

    好的,现在我遇到了编译错误,因为它是 shows on official tutorial of Xamarin bindings,我需要检查 Fields[Verify] 属性,解决问题后需要删除这个 Attribute ,还添加 Protocol 属性等。

    ApiDefinition.cs的新版本:

       [Static]
        //[Verify(ConstantsInterfaceAssociation)]
        partial interface Constants
        {
            // extern double OSMapKitAdapterVersionNumber;
            [Field("OSMapKitAdapterVersionNumber", "__Internal")]
            double OSMapKitAdapterVersionNumber { get; }
    
            // extern const unsigned char [] OSMapKitAdapterVersionString;
            [Field("OSMapKitAdapterVersionString", "__Internal")]
            IntPtr OSMapKitAdapterVersionString { get; }
        }
    
        // @interface OSTileOverlay : MKTileOverlay
        [BaseType(typeof(MKTileOverlay))]
        [Protocol]
        interface OSTileOverlay
        {
            // @property (assign, nonatomic) BOOL clipOverlay;
            [Export("clipOverlay")]
            bool ClipOverlay { get; set; }
    
            // -(instancetype _Nonnull)initWithAPIKey:(NSString * _Nonnull)apiKey product:(OSMapProduct)product __attribute__((objc_designated_initializer));
            [Export("initWithAPIKey:product:")]
            [DesignatedInitializer]
            IntPtr Constructor(string apiKey, OSMapProduct product);
        }
    
        // @interface OSMapViewRegionRestriction : NSObject
        [BaseType(typeof(NSObject))]
        [Protocol]
        interface OSMapViewRegionRestriction
        {
            // @property (readonly, nonatomic) MKCoordinateRegion initialRegion;
            [Export("initialRegion")]
            MKCoordinateRegion InitialRegion { get; }
    
            // -(void)updateMapViewRegionIfRequired:(MKMapView * _Nonnull)mapView;
            [Export("updateMapViewRegionIfRequired:")]
            void UpdateMapViewRegionIfRequired(MKMapView mapView);
        }
    
        // @interface OSMapKitAdapter : NSObject
        [BaseType(typeof(NSObject))]
        [Protocol]
        interface OSMapKitAdapter
        {
        }
    

    结构体的新版本:

    #if __UNIFIED__
    [Native]
    public enum OSMapProduct : long
    {
        Road,
        Outdoor,
        Light,
        Night
    }
    #endif 
    static class CFunctions
    {
        // extern NSString * NSStringFromOSMapProduct (OSMapProduct product);
        [DllImport ("__Internal")]
        //[Verify (PlatformInvoke)]
        static extern NSString NSStringFromOSMapProduct (OSMapProduct product);
    
        // extern CLLocationCoordinate2D OSUpperLeftCorner ();
        [DllImport ("__Internal")]
        //[Verify (PlatformInvoke)]
        static extern CLLocationCoordinate2D OSUpperLeftCorner ();
    
        // extern CLLocationCoordinate2D OSLowerRightCorner ();
        [DllImport ("__Internal")]
        //[Verify (PlatformInvoke)]
        static extern CLLocationCoordinate2D OSLowerRightCorner ();
    
        // extern MKMapRect OSMapRectForUK ();
        [DllImport ("__Internal")]
        //[Verify (PlatformInvoke)]
        static extern MKMapRect OSMapRectForUK ();
    }
    

    问题是我遇到了这个错误:

    错误 MT5214:本机链接失败,未定义符号:_OSMapKitAdapterVersionNumber。此符号由托管成员 OSTest.Constants.OSMapKitAdapterVersionNumber 引用。请验证是否已引用所有必要的框架并链接本机库。 (MT5214)

    错误 MT5214:本机链接失败,未定义符号:_OSMapKitAdapterVersionString。此符号由托管成员 OSTest.Constants.OSMapKitAdapterVersionString 引用。请验证是否已引用所有必要的框架并链接本机库。 (MT5214)

    错误 MT5202:本机链接失败。请查看构建日志。 (MT5202)

    _Xamarin.Bindings_ 项目的 .csproj 文件看起来如何:

     <ItemGroup>
        <Reference Include="System" />
        <Reference Include="Xamarin.iOS" />
      </ItemGroup>
      <ItemGroup>
        <Compile Include="Properties\AssemblyInfo.cs" />
        <Compile Include="OSTransformation.framework.linkwith.cs" />
      </ItemGroup>
      <ItemGroup>
        <ObjcBindingApiDefinition Include="ApiDefinition.cs" />
      </ItemGroup>
      <ItemGroup>
        <ObjcBindingCoreSource Include="Structs.cs" />
      </ItemGroup>
      <ItemGroup>
        <NativeReference Include="OSTransformation.framework">
          <IsCxx>False</IsCxx>
          <Kind>Framework</Kind>
     </NativeReference>
          <NativeReference Include="..\..\..\MyPath\OSMapKitAdapter\libOSMapKitAdapter.a">
            <Kind>Static</Kind>
            <SmartLink>False</SmartLink>
          </NativeReference>
      </ItemGroup>
      <Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.ObjCBinding.CSharp.targets" />
    </Project>
    

    它在真实设备上WORKS,但在模拟器上仍然会出现这种奇怪的错误。

    更新:

    只需确保您在链接器上选择了“仅链接框架 SDK”并作为例外工作!

    【讨论】:

      【解决方案2】:

      这个库是用纯 ObjC 编写的。 Swift 写的例子只有一个。 鉴于库代码比较少,建议你重新写成C#

      【讨论】:

      • 感谢您的回复,但正如我上面所说,我很难从 ObjC 复制到 C#。是的,我错了,两者都是 ObjC。无论如何,我已经制作了一个静态库,不幸的是它不起作用。我将更新我的主要问题。敬请期待!
      猜你喜欢
      • 2016-04-16
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 2015-11-28
      • 2016-12-20
      相关资源
      最近更新 更多