- SDK 다운로드및 API 신청 : 문서 참조및 API 신청
- Sample 다운로드 : 다운로드
*Note : 네이티브 앱 키 발급 및 Bundle ID 등록하기에 대한 내용 확인
추가 참조 라이브러리에 대한 내용 확인 <- native binding 프로젝트 assembly 정보 설정에 참고가 됨
- Library : Xamarin.iOS Binding Library 용 DaumMap.framework Convert 프로젝트
- App : Xamarin iOS 용 다음 지도 Sample
- sharpie 를 이용하여 ApiDefinitions.cs 및 StructsAndEnums.cs 파일 생성하기 (on MacOS) (sharpie 사용법은 링크를 클릭해보시기 바랍니다. 여러 옵션이 있으나 DaumMap.framework 변환시 가장 무난하게 변경된 옵션만 표시하도록 하겠습니다.)
sharpie bind -output TempBinding -namespace DaumMap.iOS -sdk iphoneos11.3 -scope DaumMap.framework/Versions/A/Headers DaumMap.framework/Versions/A/Headers/*.h -c
- (sharpie 를 실행하면 다음과 같은 화면이 보이더라도 당황화지 마세요!!)
- 옵션중 -sdk iphoneos11.3 <- pc에 설치되어 있는 sdk 버전으로 변경 (sdk 버전 확인:터미널 -> xcodebuild -showsdks)
- ApiDefinitions.cs , StructsAndEnums.cs 파일이 생성확인
- Binding Analysis 내용 확인 <- 코드 수정에 대한 가이드
- Native Binding 프로젝트 생성
- New Solution -> iOS 라이브러리 -> 바인딩 라이브러리 생성
- DaumMap.framework 내의 DaumMap 파일을 찾아 확장자 .a 를 추가 한다 -> DaumMap.a
변경전 | 변경후 |
---|---|
- 네이티브 참조에 DaumMap.framework를 참조해도 동일한 결과를 얻을 수 있음
- 파일이 추가 되면서 DaumMap.linkwith.cs 파일이 자동으로 생성
- 참조 : Binging objective-c libraries , ObjCRuntime.LinkWithAttribute Class
- DaumMap.linkwith.cs 파일 수정.
- 다음의 문서가이드를 보면 참조해야할 framework 항목들을 확인 할 수 있음.
using ObjCRuntime;
[assembly: LinkWith("DaumMap.a",
SmartLink = true,
ForceLoad = true,
Frameworks = "OpenGLES SystemConfiguration CoreLocation QuartzCore UIKit Foundation CoreGraphics",
LinkerFlags = "-lstdc++.6 -lxml2 -lsqlite3")]
- sharpie 로 생성하 ApiDefinitions.cs , StructsAndEnums.cs 파일 내용 복사 또는 Drag and Drop로 프로젝트에 파일 추가
-
sharpie로 생성된 파일은 최종 결과 파일이 아니고, Binging objective-c libraries 등을 참조하여 내용에 맞게 수정해 주어야 함
- 예 :
변경전 코드 ApiDefinition.cs 파일 [BaseType (typeof(NSObject))] interface MTMapPoint { ... // -(MTMapPointGeo)mapPointGeo; // -(void)setMapPointGeo:(MTMapPointGeo)mapPointGeo; [Export ("mapPointGeo")] [Verify (MethodToProperty)] MTMapPointGeo MapPointGeo { get; set; } <- MTMapPointGeo 타입 getter/setter (C#의 Property 형태로 코드 생성) ... } MTMapPointGeo 는 Structs.cs 파일에 정의 되어 있는 struct type [StructLayout (LayoutKind.Sequential)] public struct MTMapPointGeo { public double Latitude; public double Longitude; } setter 의 경우 제대로 동작하지만 getter 의 경우 System.InvalidProgramException : Invalid IL code in ~ 형태의 에러발생
변경후 [BaseType(typeof(NSObject))] public interface MTMapPoint { 주석 처리 ... // -(MTMapPointGeo)mapPointGeo; // -(void)setMapPointGeo:(MTMapPointGeo)mapPointGeo; //[Export("mapPointGeo")] //[Internal] //MTMapPointGeo MapPointGeo { get; set; } ... } * [Internal] Attribute 는 Method 가 외부로 노출이 안되도록 함 Messaging.cs 파일 추가 namespace DaumMap.iOS { internal class Messaging { const string LIBOBJC_DYLIB = "/usr/lib/libobjc.dylib"; [DllImport(LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")] Attribute 추가 -> [return: MarshalAs(UnmanagedType.Struct)] public extern static global::DaumMap.iOS.MTMapPointGeo MTMapPointGeo_objc_msgSend(IntPtr receiver, IntPtr selector); [DllImport(LIBOBJC_DYLIB, EntryPoint = "objc_msgSendSuper")] Attribute 추가 -> [return: MarshalAs(UnmanagedType.Struct)] public extern static global::DaumMap.iOS.MTMapPointGeo MTMapPointGeo_objc_msgSendSuper(IntPtr receiver, IntPtr selector); [DllImport(LIBOBJC_DYLIB, EntryPoint = "objc_msgSend_stret")] public extern static void MTMapPointGeo_objc_msgSend_stret(out global::DaumMap.iOS.MTMapPointGeo retval, IntPtr receiver, IntPtr selector); [DllImport(LIBOBJC_DYLIB, EntryPoint = "objc_msgSendSuper_stret")] public extern static void MTMapPointGeo_objc_msgSendSuper_stret(out global::DaumMap.iOS.MTMapPointGeo retval, IntPtr receiver, IntPtr selector); [DllImport(LIBOBJC_DYLIB, EntryPoint = "objc_msgSend")] public extern static void void_objc_msgSend_MTMapPointGeo(IntPtr receiver, IntPtr selector, global::DaumMap.iOS.MTMapPointGeo arg1); [DllImport(LIBOBJC_DYLIB, EntryPoint = "objc_msgSendSuper")] public extern static void void_objc_msgSendSuper_MTMapPointGeo(IntPtr receiver, IntPtr selector, global::DaumMap.iOS.MTMapPointGeo arg1); ... } } Extensions.cs 파일에 아래와 같은 추가 코드 생성 ... public partial class MTMapPoint { public MTMapPointGeo MapPointGeo { [Export("mapPointGeo")] get { MTMapPointGeo ret; if (IsDirectBinding) { if (Runtime.Arch == Arch.DEVICE) { if (IntPtr.Size == 8) { ret = global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSend(this.Handle, Selector.GetHandle("mapPointGeo")); } else { global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSend_stret(out ret, this.Handle, Selector.GetHandle("mapPointGeo")); } } else if (IntPtr.Size == 8) { ret = global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSend(this.Handle, Selector.GetHandle("mapPointGeo")); } else { global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSend_stret(out ret, this.Handle, Selector.GetHandle("mapPointGeo")); } } else { if (Runtime.Arch == Arch.DEVICE) { if (IntPtr.Size == 8) { ret = global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSendSuper(this.SuperHandle, Selector.GetHandle("mapPointGeo")); } else { global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSendSuper_stret(out ret, this.SuperHandle, Selector.GetHandle("mapPointGeo")); } } else if (IntPtr.Size == 8) { ret = global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSendSuper(this.SuperHandle, Selector.GetHandle("mapPointGeo")); } else { global::DaumMap.iOS.Messaging.MTMapPointGeo_objc_msgSendSuper_stret(out ret, this.SuperHandle, Selector.GetHandle("mapPointGeo")); } } return ret; } [Export("setMapPointGeo:")] set { if (IsDirectBinding) { global::DaumMap.iOS.Messaging.void_objc_msgSend_MTMapPointGeo(this.Handle, Selector.GetHandle("setMapPointGeo:"), value); } else { global::DaumMap.iOS.Messaging.void_objc_msgSendSuper_MTMapPointGeo(this.SuperHandle, Selector.GetHandle("setMapPointGeo:"), value); } } } ... } 실제 코드 호출시 var mapPointGeo = mapView.MapCenterPoint.MapPointGeo;
- 경우에 따라 추가코드 생성 (예 : Extension.cs)
- iOS 용 App 프로젝트 생성 -> Native Binding 프로젝트 참조
- 다음 API 신청시 등록된 iOS Bundle ID 와 APP KEY 를 동일하게 설정해 주어야 지도 서비스가 제대로 동작합니다.
info.plist -> Bundle ID
그리고 Info.plist 파일에 다음과 같은 항목으로 발급 받은 APP KEY 를 설정
- Key name: KAKAO_APP_KEY
- Value Type : String
- Value : 발급 받은 APP KEY
코드 예제
using NMapViewerSDK.iOS;
...
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
isMapRotationUsing = false;
mapView = new MTMapView(new CGRect(0, 0, View.Frame.Width, View.Frame.Height));
View.AddSubview(mapView);
this.NavigationItem.SetRightBarButtonItem(new UIBarButtonItem("메뉴", UIBarButtonItemStyle.Plain, OnClickMenuButton), true);
}
- Polyline 예제의 경우 모든라인 지우기 (mapView.RemoveAllPolylines()) 명령을 호출해도 라인이 그대로 보여짐. 내 PC 환경의 영향인지를 모르겠으나 원본소스예제를 실행해도(Xcode 9.3) 마찬가지 결과임.