Связующие библиотеки Xamarin.iOS / родные структуры

По какой-то причине мне нужно использовать этот встроенный фреймворк в моем приложении Xamarin.iOS, и возникает проблема, заключающаяся в том, что я понятия не имею, как правильно делать привязки.


Итак, как я правильно понял, эта структура также использует другую структуру, и я немного запутался, что именно мне нужно делать?


Вопросы:

  1. Нужно ли реализовывать статическую библиотеку (возможно ли это сделать с нативными фреймворками), как это показано в официальной документации Xamarin?
  2. Могу ли я сделать привязки для собственного фреймворка, который тоже использует другой фреймворк, или мне нужно реализовать их отдельно?
  3. Может быть, мне следует переписать все эти нативные фреймворки в версию C#?!? (Но здесь возникает другая проблема, фреймворки используют ObjC и для меня трудно воспроизвести в C#)
  4. Каков наилучший подход для достижения моей цели? (Возможно, он не описан, и вы можете рассказать мне больше).

Любой совет? Спасибо!

2 ответа

Решение

Хорошо, наконец-то я создал статическую библиотеку, но что-то идет не так, и в данный момент я не могу использовать ее в эмуляторе.:(

Я шаг за шагом объясню, как я сделал статическую библиотеку:

  • Я получил все исходные файлы из этого хранилища.
  • В Xcode IDE я сделал проект статической библиотеки, и после этого я скопировал все исходные файлы из репозитория в мой проект.

  • Через Карфаген я загрузил этот фреймворк (как я уже объяснил, исходные файлы используют этот фреймворк), а также я добавил новую категорию в Фазы сборки -> Копировать файлы (где я выбрал фреймворк) в мою статическую библиотеку. И успешно собран (на цели развертывания 10.2)

    Img,

  • Затем я сделал 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
  • Затем я создал проект Binding Library в Xamarin и добавил Fat Binary Static Library в качестве собственной ссылки (я покажу мой файл.csproj ниже), а также я поместил то же самое для фреймворка (я скопировал его в путь к проекту), который связан внутри статической библиотеки (может быть, это избыточно?)


    Кроме того, я сделал дополнительный файл, который называется OSTransformation.framework.linkwith.cs с кодом:

Связать с

  • С помощью Objective Sharpie были сгенерированы ApiDefinition.cs и Structs.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 ();
}

Хорошо, теперь я получил ошибки компиляции и, как видно из официального руководства по привязкам Xamarin, мне нужно проверить поля с атрибутом [Verify], и после решения проблемы с ними необходимо удалить этот атрибут, добавить атрибут 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
    {
    }

Новая версия Structs:

#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)

Как выглядит мой файл .csproj проекта _ Xamarin.Bindings_:

 <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>

Это работает на реальном устройстве, но на эмуляторе все еще получают ошибки, это странные ошибки.

UPD:

Просто убедитесь, что вы выбрали "Link Framework SDK only" на компоновщике и работали в порядке исключения!

Эта библиотека написана на чистом ObjC. Есть только один пример, написанный Swift. Ввиду того, что код библиотеки относительно невелик, рекомендую переписать на C #

Другие вопросы по тегам