【備注(轉載請說明出處,"http://www.cnblogs.com/RedSky/p/6679443.html","如果本文對你有幫助,請給個贊")】
本文將教你如何在Xamarin中使用極光JPush對IOS進行推送。
要開發iOS應用程序,你需要一台mac,Xamarin並不能支持在Windows上單獨開發iOS;要進行推送測試,這只能在真機上進行測試,所以你還需要一部iPhone手機。
簡要步驟
- 配置開發環境及工具
- 申請蘋果開發者證書,App IDs,推送開發版證書,以及配置文件
- 配置極光環境
- 使用Xcode建立靜態類庫配置極光sdk
- 將靜態類庫生成.a文件庫
- 將靜態類庫生成ApiDefinition.cs和StructsAndEnums.cs
- 在Xcode建立應用項目
- 建立Xamarin.iOS項目
- 建立Native Library
- 引用Native Library
- 測試
1.配置開發環境及工具
這我們的開發環境及工具:
-
- Visual Studio 2013 Update 5
- Xamarin for Visual Studio 4.3.0.784
- Xcode 8.3
- 手機iPhone 4 A1332
- JPush iOS sdk 3.0.2
- Objective Sharpie(下載鏈接:https://xamarin.azureedge.net/objective-sharpie/ObjectiveSharpie.pkg)
- Windows 10
- macOS 10.12.3
這里內容過長不作詳細講解,可到網上參考其他資料進行。
2.申請蘋果開發者證書,App IDs,推送開發版證書,以及配置文件
這里內容過長不作詳細教學,可到網上參考其他資料進行。這步驟完成后下載配置文件到mac本機。
3.配置極光環境
注冊極光開發者賬號,新建應用,將推送開發版證書上傳到應用,下載客戶端iOS sdk。具體步驟可在極光官網查看。
4.使用Xcode建立靜態類庫配置極光sdk
在mac里打開Xcode新建項目,這里我們選擇Static Library,點擊Next。

項目名稱我們隨便填一個,這里我們使用PushLibrary,然后完成,完成后會進入到項目界面。
接下來我們給項目引入極光官網的iOS sdk,引入后項目結構如下,注意,這里我們要將sdk的Lib文件夾復制到項目目錄下后在添加到項目中,再將JPUSHService.h復制到PushLibrary.h同一目錄下,引用jcore-ios-1.1.1.a, jpush-ios-3.0.2.a, JPUSHService.h要引用復制到項目目錄里的文件。

這里有兩個文件注意一下(libresolv.9.dylib, libz.1.dylib),官方是libz.tbd和libresolv.tbd,如果你添加這兩個文件后嘗試編譯未通過,請按下面方法。
引用libz.tbd與引用libresolv.tbd方法相同,這里我們以libz.tbd為例。點擊你的libz.tbd文件,在右側文檔里看見install-name:

這里我們要添加libz.1.dylib,如果你的跟圖片上不一樣,請使用你自己的。在linking Binary中添加

在彈出窗口中選擇左下角And Other...

在新彈出窗口內右側搜索框里我們填上libz.1.dylib

這里我們選擇其中一個,Open。
這就完成了,libresolv.tbd的處理方法一樣。
我們進行編譯,編譯通過。
5.將靜態類庫生成.a文件庫
這里我們可以參考Xamarin官方文檔,參考鏈接:https://developer.xamarin.com/guides/ios/advanced_topics/native_interop/。
我們需要生成arm64, armv7, armv7s三個版本的.a文件庫,然后再將它們合並成一個文件庫。
首先找到我們靜態類庫項目目錄,通過右鍵項目>Show in Finder;右鍵項目文件>取得資訊(繁體版系統會顯示取得資訊,如果你的是簡體版可能不一樣,就是查看文件信息的意思)。


我們選擇“位置“復制路徑,在mac命令器里輸入項目目錄
cd /mydir/mydir
回車進入項目目錄;接着輸入命令生成arm64的.a文件:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project PushLibrary.xcodeproj -target PushLibrary -sdk iphoneos -arch arm64 -configuration Release clean build
成功后進入build目錄iphoneos目錄里找到libPushLibrary.a文件,重命名為libPushLibrary-arm64.a。
生成armv7命令:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project PushLibrary.xcodeproj -target PushLibrary -sdk iphoneos -arch armv7 -configuration Release clean build
成功后進入build目錄iphoneos目錄里找到libPushLibrary.a文件,重命名為libPushLibrary-armv7.a。
生成armv7s命令:
/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild -project PushLibrary.xcodeproj -target PushLibrary -sdk iphoneos -arch armv7s -configuration Release clean build
成功后進入build目錄iphoneos目錄里找到libPushLibrary.a文件,重命名為libPushLibrary-armv7s.a。
好,到這里我們通過”cd“命令進入到這三個文件所在目錄,輸入如下命令:
lipo -create -output libPushLibrary.a libPushLibrary-arm64.a libPushLibrary-armv7.a libPushLibrary-armv7s.a
回車后就會生成我們需要的libPushLibrary.a文件。

6.將靜態類庫生成ApiDefinition.cs和StructsAndEnums.cs
這里我們需要用到Objective Sharpie,下載鏈接在上文已經提供,下載后安裝在mac中。
現在我們在mac命令器中使用sharpie生成ApiDefinition.cs和StructsAndEnums.cs。
sharpie bind -sdk=iphoneos10.2 [項目目錄]/PushLibrary/*.h
-sdk是iphoneos版本號,這里你可以通過命令
sharpie bind -sdks
獲取自己已安裝的sdk版本號,在這里我們使用已安裝的iphoneos10.2。
如果沒有錯誤的話,你會得到ApiDefinition.cs和StructsAndEnums.cs。
現在你得到三個文件libPushLibrary.a, ApiDefinition.cs和StructsAndEnums.cs。

7.在Xcode建立應用項目
這里我們選擇Single View Application就可以。

點擊Next>

上面圖片里注意命名規則,如果注冊App IDs時Bundle Identifier是com.XXX.xxx,那么Product Name就是對應的xxx。填寫完成點擊Next。
在項目配置里添加之前申請開發者證書時下載的配置文件:

編譯項目

在mac機上的操作到這里算結束。
8.建立Xamarin.iOS項目
在Visual Studio里新建一個項目,項目名稱隨意,生成后我們打開項目屬性。

平台選擇iPhone,應用名稱和識別碼填寫對應Bundle Identifier;滾動條往下拖。

勾選中啟用背景模式,遠端通知。勾選后才能獲得通知權限。
在iOS Bundle Signing選擇身份和配置文件:
編譯項目。
9.建立Native Library
右鍵解決方案新建項目,選擇

項目名稱隨意命名,新建Native Library后將之前生成的libPushLibrary.a文件添加到項目中。

添加后會在.a文件下自動生成個libPushLibrary.linkwith.cs文件,我們打開這個文件,"[assembly: ..."一行替換為:
[assembly: LinkWith("libPushLibrary.a", Frameworks="AdSupport CFNetwork CoreFoundation CoreGraphics CoreTelephony UIKit Foundation Security SystemConfiguration UserNotifications", LinkerFlags="-ObjC -lz.1 -lresolv.9", LinkTarget = LinkTarget.Arm64 | LinkTarget.ArmV7 | LinkTarget.ArmV7s, ForceLoad = true, SmartLink = true)]
注意這里-lz.1 -lresolv.9要對應之前你添加的libz和libresolv,libz寫作lz,前有'-'。
完成后再將ApiDefinition.cs和StructsAndEnums.cs里的代碼復制到對應cs文件里,注意命名空間引用。在ApiDefinition.cs里找到有Verify標簽([Verify(...)])的行,將這些行刪掉,將[IOS(...)]標簽注釋掉

注釋或刪除函數SetTags(NSSet tags, string alias, Selector cbSelector, NSObject theTarget);這個方法重復了,注釋掉過期的函數。

StructsAndEnums.cs里nuint替換成uint。

編譯項目,到這里就完成了Native Library的創建,完成了極光sdk的引用。
10.引用Native Library
現在在我們的Xamarin.iOS應用項目里引用Native Library項目。
我們創建兩個類文件用來注冊極光推送id和接收推送消息的類:

代碼如下:
JPushInterface.cs:
using Foundation; using IOSNativeLibrary; using System; using System.Collections.Generic; using System.Text; using UserNotifications; namespace App1.iOS.Notification.JPush { public class JPushInterface : IOSNativeLibrary.JPUSHRegisterDelegate { internal static string JPushAppKey = "我的極光AppKey"; internal static string Channel = ""; JPushRegisterEntity entity { get; set; } public void Register(AppDelegate app, NSDictionary options) { //注冊apns遠程推送 string advertisingId = AdSupport.ASIdentifierManager.SharedManager.AdvertisingIdentifier.AsString(); this.entity = new JPushRegisterEntity(); this.entity.Types = 1 | 2 | 3;//entity.Types = (nint)(JPAuthorizationOptions.Alert) | JPAuthorizationOptions.Badge | JPAuthorizationOptions.Sound; JPUSHService.RegisterForRemoteNotificationConfig(entity, this); JPUSHService.SetupWithOption(options, JPushAppKey, Channel, true, advertisingId); JPUSHService.RegistrationIDCompletionHandler(app.GetRegistrationID); } /// <summary> /// 前台收到通知,IOS10 support /// </summary> /// <param name="center"></param> /// <param name="notification"></param> /// <param name="completionHandler"></param> public override void WillPresentNotification(UserNotifications.UNUserNotificationCenter center, UserNotifications.UNNotification notification, Action<nint> completionHandler) { Console.WriteLine("WillPresentNotification:"); var content = notification.Request.Content; var userInfo = notification.Request.Content.UserInfo; if (typeof(UserNotifications.UNPushNotificationTrigger) == notification.Request.Trigger.GetType()) {//遠程通知 System.Console.WriteLine(" 收到遠程通知,Title:{0} -SubTitle:{1}, -Body:{2}", content.Title, content.Subtitle, content.Body); this.AddNotificationToView(content); JPUSHService.HandleRemoteNotification(userInfo); } else {//本地通知 } if (completionHandler != null) { completionHandler(2);//UNNotificationPresentationOptions: None = 0,Badge = 1,Sound = 2,Alert = 4, } } /// <summary> /// 后台收到通知 /// </summary> /// <param name="center"></param> /// <param name="response"></param> /// <param name="completionHandler"></param> public override void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, Action completionHandler) { Console.WriteLine("DidReceiveNotificationResponse:"); var content = response.Notification.Request.Content; var userInfo = response.Notification.Request.Content.UserInfo; if (typeof(UserNotifications.UNPushNotificationTrigger) == response.Notification.Request.Trigger.GetType()) {//遠程通知 System.Console.WriteLine(" 收到遠程通知,Title:{0} -SubTitle:{1}, -Body:{2}", content.Title, content.Subtitle, content.Body); this.AddNotificationToView(content); JPUSHService.HandleRemoteNotification(userInfo); } else {//本地通知 } if (completionHandler != null) { completionHandler(); } } /// <summary> /// 通知添加到視圖 /// </summary> /// <param name="content"></param> public void AddNotificationToView(UNNotificationContent content) { App1.ViewModel.PushsPageViewModel.Item item = new ViewModel.PushsPageViewModel.Item() { Id = content.CategoryIdentifier, Text = content.Title, Detail = content.Body, }; App1.ViewModel.PushsPageViewModel.Instance.AddItem(item); } } }
JPushRegisterEntity.cs:
using Foundation; using IOSNativeLibrary; using System; using System.Collections.Generic; using System.Text; namespace App1.iOS.Notification.JPush { public class JPushRegisterEntity : JPUSHRegisterEntity { public override NSSet Categories { get { return base.Categories; } set { base.Categories = value; } } public override nint Types { get { return base.Types; } set { base.Types = value; } } } }
你發現這兩個類都是繼承自Native Library。
現在轉到AppDelegate.cs中,我們先創建個字段jPushRegister,用來實例化極光注冊和推送接收:

在FinishedLaunching方法里我們這么寫:
public override bool FinishedLaunching(UIApplication app, NSDictionary options) { global::Xamarin.Forms.Forms.Init(); LoadApplication(new App(Model.BasePlatform.Instance)); //注冊apns遠程推送 if (options == null) options = new NSDictionary(); jPushRegister = new JPushInterface(); jPushRegister.Register(this, options); this.RegistLogin(options); return base.FinishedLaunching(app, options); }
這里我們使用的是Xamarin.Forms框架,如果你的項目不是,那可能看起來會不太一樣。
目前極光推送是通過APNS向iOS推送通知的,那么我們要想推送成功就得還需要注冊APNS獲取APNS的推送設備id。
我們在AppDelegate類下添加如下代碼實現注冊:
/// <summary> /// 注冊apns遠程推送 /// </summary> /// <param name="launchOptions"></param> protected void RegistLogin(NSDictionary launchOptions) { string systemVersion = UIDevice.CurrentDevice.SystemVersion.Split('.')[0]; Console.WriteLine("System Version: " + UIDevice.CurrentDevice.SystemVersion); //iOS10以上的注冊方式 if (float.Parse(systemVersion) >= 10.0) { UNUserNotificationCenter center = UNUserNotificationCenter.Current; center.RequestAuthorization((UNAuthorizationOptions.CarPlay | UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound | UNAuthorizationOptions.Badge), (bool arg1, NSError arg2) => { if (arg1) Console.WriteLine("ios 10 request notification success"); else Console.WriteLine("IOS 10 request notification failed"); }); } //iOS8以上的注冊方式 else if (float.Parse(systemVersion) >= 8.0) { UIUserNotificationSettings notiSettings = UIUserNotificationSettings.GetSettingsForTypes(UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert, null); UIApplication.SharedApplication.RegisterUserNotificationSettings(notiSettings); } //iOS8以下的注冊方式,這里我們最低版本是7.0以上 else { UIRemoteNotificationType myTypes = UIRemoteNotificationType.Alert | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Badge; UIApplication.SharedApplication.RegisterForRemoteNotificationTypes(myTypes); } UIApplication.SharedApplication.RegisterForRemoteNotifications(); if (launchOptions != null) { NSDictionary remoteNotification = (NSDictionary)(launchOptions.ObjectForKey(UIApplication.LaunchOptionsRemoteNotificationKey)); if (remoteNotification != null) { Console.WriteLine(remoteNotification); //這里是跳轉頁面用的 //this.goToMessageViewControllerWith(remoteNotification); } } } public override void DidRegisterUserNotificationSettings(UIApplication application, UIUserNotificationSettings notificationSettings) { application.RegisterForRemoteNotifications(); } /// <summary> /// 注冊成功獲得token /// </summary> /// <param name="application"></param> /// <param name="deviceToken"></param> public override void RegisteredForRemoteNotifications(UIApplication application, NSData deviceToken) { JPUSHService.RegisterDeviceToken(deviceToken); // Get current device token var DeviceToken = deviceToken.Description; if (!string.IsNullOrWhiteSpace(DeviceToken)) { DeviceToken = DeviceToken.Trim('<').Trim('>'); } // Get previous device token var oldDeviceToken = NSUserDefaults.StandardUserDefaults.StringForKey("PushDeviceToken"); // Has the token changed? if (string.IsNullOrEmpty(oldDeviceToken) || !oldDeviceToken.Equals(DeviceToken)) { //TODO: Put your own logic here to notify your server that the device token has changed/been created! } // Save new device token NSUserDefaults.StandardUserDefaults.SetString(DeviceToken, "PushDeviceToken"); System.Console.WriteLine(DeviceToken); } /// <summary> /// 注冊token失敗 /// </summary> /// <param name="application"></param> /// <param name="error"></param> public override void FailedToRegisterForRemoteNotifications(UIApplication application, NSError error) { new UIAlertView("注冊通知失敗", error.LocalizedDescription, null, "OK", null).Show(); } public void GetRegistrationID(int resCode, NSString registrationID) { if (resCode == 0) { Console.WriteLine("RegistrationID Successed: {0}", registrationID); App1.ViewModel.UserCenterPageViewModel.Instance.RegistId = registrationID; } else Console.WriteLine("RegistrationID Failed. ResultCode:{0}", resCode); }
到了這里你就可以在手機上進行測試了。
【備注(轉載請說明出處,"http://www.cnblogs.com/RedSky/p/6679443.html","如果本文對你有幫助,請給個贊")】
