私有Pods封裝個推SDK功能(解決方案)

来源:http://www.cnblogs.com/wujy/archive/2016/07/07/5651089.html
-Advertisement-
Play Games

一:運用場景 公司中同時有好幾個APP在開發,而且每個APP都有使用到集成個推SDK來處理消息的功能,以前的做法是每個APP都去集成併在AppDelegate處理一些SDK的代碼,包含個推基礎配置、消息接收處理、遠程信息處理、蘋果通知註冊等等;後來你會發現其實在這部分內容中只有配置跟消息接收時存在差 ...


一:運用場景

公司中同時有好幾個APP在開發,而且每個APP都有使用到集成個推SDK來處理消息的功能,以前的做法是每個APP都去集成併在AppDelegate處理一些SDK的代碼,包含個推基礎配置、消息接收處理、遠程信息處理、蘋果通知註冊等等;後來你會發現其實在這部分內容中只有配置跟消息接收時存在差異,畢竟接收消息用來處理不同的業務邏輯問題;今天要介紹的功能就是把相同或不變的內容封裝起來,開放出差異給每個APP的AppDelegate進行處理;而對於這部分相同的封裝運用私有Pods進行管理,所以封裝後的個推使用起來很簡單,哪怕你對個推都不瞭解也能在一分鐘搞定個推集成功能;

實現這個封裝運用下麵幾個知識點,私有Pods的搭建、AppDelegate方法的註入(採用插件XAspect 地址:https://github.com/xareelee/XAspect)

 

二:集成效果

1:首先瞭解一某個工程內的AppDelegate的代碼,從下麵的代碼你是否已經找不到個推SDK那些代碼及你消息註冊等等;只在didFinishLaunchingWithOptions中增加一個配置,其它兩個方法是用來處理消息的內容;

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    //配置個推信息
    jiaGTConfigManager *gtConfig=[jiaGTConfigManager sharedInstance];
    gtConfig.jiaGTAppId=@"C83sm0U3xt5D5GUYqkfk53";
    gtConfig.jiaGTAppKey=@"13OydrjIuC8TZliF43hRS5";
    gtConfig.jiaGTAppSecret=@"gdgYQJSUNa5pIQB2icrCt1";
    
    ViewController *logInVc = [[ViewController alloc]init];
    self.window.rootViewController = logInVc;
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];
    
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}


/**
 *  @author wujunyang, 16-07-07 16:07:25
 *
 *  @brief  處理個推消息
 *
 *  @param notificationObject <#notificationObject description#>
 */
-(void)gtNotification:(NSObject *)notificationObject
{
    if (notificationObject) {
        NSNotification *curNotification=(NSNotification *)notificationObject;
        NSLog(@"%@",curNotification.userInfo[@"payload"]);
        NSLog(@"-----接收到個推通知------");
    }
}


/**
 *  @author wujunyang, 16-07-07 16:07:40
 *
 *  @brief  處理遠程蘋果通知
 *
 *  @param notificationObject <#notificationObject description#>
 */
-(void)receiveRemoteNotification:(NSObject *)notificationObject
{
    if (notificationObject) {
        NSNotification *curNotification=(NSNotification *)notificationObject;
        UIAlertView *alert=[[UIAlertView alloc]initWithTitle:@"您有一條新消息" message:[NSString stringWithFormat:@"%@,%@",curNotification.userInfo[@"payload"],curNotification.userInfo[@"message"]] delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"確定", nil];
        [alert show];
    }
}

 

2:工程中的AppDelegate繼承於我們定義的父類jiaAppDelegate,關於jiaAppDelegate是什麼,jiaGTConfigManager又是乾什麼;你可以接著往下看;

#import <UIKit/UIKit.h>
#import "jiaAppDelegate.h"
#import "jiaGTConfigManager.h"


@interface AppDelegate :jiaAppDelegate<UIAlertViewDelegate>

@end

 

3:引入Pod指令

link_with ['WjyTestClassDemo']

source 'https://github.com/CocoaPods/Specs.git'        #官方倉庫地址
source ‘https://github.com/wujunyang/WjySpecs.git’        #私有倉庫地址

platform :ios, "7.0"

pod "QiJIAGTSDK"

 

4:查看效果圖

 

到這邊如果你只是運用,那麼就可以結束了;就算你不懂個推也已經搞定集成功能;

 

三:實現過程

為了實現上面這個簡化版的集成功能,我們採用的私有Pods對個推進行管理,主要是把個推SDK跟我們編寫的一些代碼進行整合;關於如果搭建私有Pods不是本文的重點,如果說你對這方面也有感興趣可以留言,我再寫一個關於搭建私有Pods的文章,網路上也有很多這方面的內容,歡迎一起交流;當然XAspect在封裝的過程中也起到很重要的作用,它的註入功能解決把原本應該在AppDelegate的代碼解耦出來;

1:首先創建一個AppDelegate,主要作用是為了其它項目的AppDelegate可以以它為基類,而我的XAspect文件就可以只對我這個父類的AppDelegate進行註入,方便後期我擴展,比如後期我可能要實現關於友盟SDK、融雲SDK的集成封裝;

jiaAppDelegate.h的文件內容:

#import <UIKit/UIKit.h>

@interface jiaAppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end

jiaAppDelegate.m的文件內容:

#import "jiaAppDelegate.h"

@interface jiaAppDelegate()

@end

@implementation jiaAppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
}

- (void)applicationWillTerminate:(UIApplication *)application {
}

-(void)dealloc
{
}

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler
{
}


-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
}
@end

是否發現其實jiaAppDelegate在這我什麼也沒有做,這樣其實就足夠了;因為這部分是比較基礎的內容,所以我也用Pods進行管理,當然你也可以再創建一個viewController的基類,讓你的工程所有的都以這為基類進行開發,有基類在手你後期一些擴展都比較好辦;

 

2:接下來將要介紹關於集成個推模塊的功能及相關代碼,也是本文的重點;首先你可以上個推的gitHub去下載它最新的SDK及一個頭文件GeTuiSdk.h;其實這兩個文件也是你平時集成個推時引入到工程的內容;如下的目錄是被我封裝後的個推目錄結構;除了那兩個文件其它就是抽離出來的內容;

 

 

2.1 jiaAppDelegate+myGt類作用

因為封裝的這個推SDK是依賴我們上面jiaAppDelegate;所以我們就可以對它進行擴展,創建這個Category是為瞭解決關於個推GeTuiSdkDelegate,因為XAspect 目前無法針對Delegate進行聲明引用;

jiaAppDelegate+myGt.h的文件內容:

#import "jiaAppDelegate.h"
#import "GeTuiSdk.h"


@interface jiaAppDelegate (myGt)<GeTuiSdkDelegate>

@end

jiaAppDelegate+myGt.m的文件內容:

#import "jiaAppDelegate+myGt.h"

@implementation jiaAppDelegate (myGt)

@end

從上面的代碼可以看出來只是引入的<GeTuiSdkDelegate>,這個Category什麼都沒有實現;

 

2.2 jiaGTConfigManager類作用

因為在個推會存在基礎配置的內容,決定創建一個配置類進行管理,它是一個單例模式;

jiaGTConfigManager.h文件的內容

#import <Foundation/Foundation.h>

@interface jiaGTConfigManager : NSObject

+ (jiaGTConfigManager *)sharedInstance;

//個推配置
@property (strong, nonatomic) NSString *jiaGTAppId;
@property (strong, nonatomic) NSString *jiaGTAppKey;
@property (strong, nonatomic) NSString *jiaGTAppSecret;

@end

jiaGTConfigManager.m文件的內容

#import "jiaGTConfigManager.h"

@implementation jiaGTConfigManager

+ (jiaGTConfigManager *)sharedInstance
{
    static jiaGTConfigManager* instance = nil;

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [jiaGTConfigManager new];
    });

    return instance;
}

@end

只是開放出三個屬性用於獲取到配置內容;

 

2.3 XAspect-GeTuiAppDelegate作用

正如前面說的個推集成的代碼是工程當前的AppDelegate不用寫,但並不代碼一直不用寫,只是被我們抽離在XAspect-GeTuiAppDelegate中,更加模塊化;XAspect插件運用起來很比較簡單,它比較一般註入的插件好處是可以多次對同一個文件相同的方法進行註入;

AspectPatch(-, BOOL, application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions)
{
    //個推初始化
    [self initLoadGeTui:launchOptions];
    
    //註冊個推通知事件
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(geTuiMessageHandling:) name:jiaGeTuiNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveRemoteMessageHandling:) name:jiaReceiveRemoteNotification object:nil];
    
    return XAMessageForward(application:application didFinishLaunchingWithOptions:launchOptions);
}

上面這段代碼就是Aspect針對didFinishLaunchingWithOptions的註入,如果有多個文件它都會進行註入到此方法中;類似的寫法就不再介紹,可以去官網進行瞭解;接收到個推消息跟遠程消息運用本地通知的方式進行獲取;

/** SDK收到透傳消息回調 */
- (void)GeTuiSdkDidReceivePayload:(NSString *)payloadId andTaskId:(NSString *)taskId andMessageId:(NSString *)aMsgId andOffLine:(BOOL)offLine fromApplication:(NSString *)appId {
    
    [self handlePushMessage:nil notification:nil];
    // [4]: 收到個推消息
    NSData *payload = [GeTuiSdk retrivePayloadById:payloadId];
    NSString *payloadMsg = nil;
    if (payload) {
        payloadMsg = [[NSString alloc] initWithBytes:payload.bytes length:payload.length encoding:NSUTF8StringEncoding];
    }
    
    NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:aMsgId,@"aMsgId", [NSNumber numberWithBool:offLine],@"offLine",appId,@"appId",payloadMsg,@"payload",nil];
    //創建通知
    NSNotification *notification =[NSNotification notificationWithName:@"jiaGeTuiNotification" object:nil userInfo:dict];
    //通過通知中心發送通知
    [[NSNotificationCenter defaultCenter] postNotification:notification];
}

在獲取到個推消息後我可以針對消息的內容先處理解析,因為本地通知的參數是一個字典,所以你可以存入你想開放的信息內容,然後再把它傳給本地通知作處理,這樣你在真正業務要使用的地方已經相當簡便;遠程通知也是類似;

而關於處理本地通知的方法讓使用的當前工程AppDelegate去實現,方法gtNotification跟receiveRemoteNotification正是開頭文章我們調用的方法;

//處理個推本地通知,判斷是否存在gtNotification方法
- (void)geTuiMessageHandling:(NSNotification *)text{
    SEL gtNotificationSelector=@selector(gtNotification:);
    if([self respondsToSelector:gtNotificationSelector])
    {
        [self performSelector:gtNotificationSelector withObject:text];
    }
}


//處理蘋果遠程通知,判斷是否存在receiveRemoteNotification方法
- (void)receiveRemoteMessageHandling:(NSNotification *)text{
    SEL receiveRemoteNotificationSelector=@selector(receiveRemoteNotification:);
    if([self respondsToSelector:receiveRemoteNotificationSelector])
    {
        [self performSelector:receiveRemoteNotificationSelector withObject:text];
    }
}

因為Aspect是要針對某個類進行註入,這個也是我們創建GeTuiAppDelegate基類的意義,這樣我都可以只針對這個基類進行註入;你可以看到XAspect-GeTuiAppDelegate開頭有這麼兩句,AtAspectOfClass就是指向類;

#define AtAspect GeTuiAppDelegate

#define AtAspectOfClass jiaAppDelegate

上面只是簡單介紹一下XAspect-GeTuiAppDelegate的內容,下麵是我會把它的完全代碼貼出來;

 

四:引入私有Pod

當我們上面封裝好的代碼就可以進行使用Pod的打包,並推到我們的私有倉庫,讓別人使用了;雖然私有Pod不是本文的重點,但也把相關的創建命令提供出來,若有不明白可以留言其它文章更新;

1:當前podspec文件內容

Pod::Spec.new do |s|

  # ―――  Spec Metadata  ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  These will help people to find your library, and whilst it
  #  can feel like a chore to fill in it's definitely to your advantage. The
  #  summary should be tweet-length, and the description more in depth.
  #

  s.name         = "QiJIAGTSDK"
  s.version      = "1.4.4"
  s.summary      = "個推iOS SDK Cocoa Pods集成庫"

  s.description  = <<-DESC
                   A longer description of getui-sdk-ios-cocoapods in Markdown format.

                   個推iOS SDK
                   DESC

  s.homepage     = "https://github.com/GetuiLaboratory/getui-sdk-ios-cocoapods"
  # s.screenshots  = "www.example.com/screenshots_1.gif", "www.example.com/screenshots_2.gif"


  # ―――  Spec License  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Licensing your code is important. See http://choosealicense.com for more info.
  #  CocoaPods will detect a license file if there is a named LICENSE*
  #  Popular ones are 'MIT', 'BSD' and 'Apache License, Version 2.0'.
  #

 # s.license      = "MIT (example)"
  s.license      = { :type => "MIT", :file => "LICENSE" }


  # ――― Author Metadata  ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Specify the authors of the library, with email addresses. Email addresses
  #  of the authors are extracted from the SCM log. E.g. $ git log. CocoaPods also
  #  accepts just a name if you'd rather not provide an email address.
  #
  #  Specify a social_media_url where others can refer to, for example a twitter
  #  profile URL.
  #

  s.author             = { "個推" => "[email protected]" }
  # Or just: s.author    = "個推實驗室"
  # s.authors            = { "個推實驗室" => "[email protected]" }
  # s.social_media_url   = "http://twitter.com/個推實驗室"

  # ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  If this Pod runs only on iOS or OS X, then specify the platform and
  #  the deployment target. You can optionally include the target after the platform.
  #

  # s.platform     = :ios
  s.platform     = :ios, "7.0"

  #  When using multiple platforms
  s.ios.deployment_target = "7.0"
  # s.osx.deployment_target = "10.7"
  # s.watchos.deployment_target = "2.0"


  # ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Specify the location from where the source should be retrieved.
  #  Supports git, hg, bzr, svn and HTTP.
  #

  s.source       = { :git => "https://github.com/wujunyang/jiaGTSDK.git", :tag => "1.4.4" }


  # ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  CocoaPods is smart about how it includes source code. For source files
  #  giving a folder will include any swift, h, m, mm, c & cpp files.
  #  For header files it will include any header in the folder.
  #  Not including the public_header_files will make all headers public.
  #

  s.source_files  = "Pod/**/*.{h,m}"
  #s.exclude_files = "Classes/Exclude"

  # s.public_header_files = "Classes/**/*.h"


  # ――― Resources ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  A list of resources included with the Pod. These are copied into the
  #  target bundle with a build phase script. Anything else will be cleaned.
  #  You can preserve files from being cleaned, please don't preserve
  #  non-essential files like tests, examples and documentation.
  #

  # s.resource  = "icon.png"
  # s.resources = "Resources/*.png"

  s.preserve_paths = "libGeTuiSdk-1.4.2.a"
  s.ios.vendored_library = "libGeTuiSdk-1.4.2.a"


  # ――― Project Linking ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  Link your library with frameworks, or libraries. Libraries do not include
  #  the lib prefix of their name.
  #

  #s.framework  = "UIKit"
  # s.frameworks = "SomeFramework", "AnotherFramework"
  s.frameworks = 'SystemConfiguration', 'CFNetwork','CoreTelephony','CoreLocation','AVFoundation','CoreBluetooth','Security','JavaScriptCore'
  s.ios.frameworks = 'SystemConfiguration', 'CFNetwork','CoreTelephony','CoreLocation','AVFoundation','CoreBluetooth','Security','JavaScriptCore'
  # s.library   = "sqlite3"
  s.ios.libraries = 'z','sqlite3.0'

  # ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
  #
  #  If your library depends on compiler flags you can set them in the xcconfig hash
  #  where they will only apply to your library. If you depend on other Podspecs
  #  you can include multiple dependencies to ensure it works.

  s.requires_arc = true

  # s.xcconfig = { "HEADER_SEARCH_PATHS" => "$(SDKROOT)/usr/include/libxml2" }
  s.dependency "jiaCore"
end

其實這個文件是拿個推那個進行簡單修改,而個推的SDK被我們用自個的git進行管理起來;主要是因為它是靜態的framework文件,所以在私有pod引入靜態的framework文件一直失敗,所以才想出這個辦法;

 

2:私有Pod檢驗跟合併推倉庫的指令

pod lib lint QiJIAGTSDK.podspec --use-libraries --verbose --allow-warnings --sources='https://github.com/CocoaPods/Specs.git,https://github.com/wujunyang/WjySpecs.git'


pod repo push WjySpecs QiJIAGTSDK.podspec --use-libraries --verbose --allow-warnings --sources='https://github.com/CocoaPods/Specs.git,https://github.com/wujunyang/WjySpecs.git'

主要是包含靜態所以指令中--use-libraries,而sources則是關於倉庫的地址,一個是公共一個是我們自個私有;

當你封裝好推到私有倉庫後,對於後面新項目你只要告訴它Pod引入命令,並配置跟處理消息就可以了;完全不用開發者瞭解關於個推的內容;

 

五:XAspect-GeTuiAppDelegate文件內容:

//
//  XAspect-LogAppDelegate.m
//  MobileProject 抽離原本應在AppDelegate的內容(個推)
//
//  Created by wujunyang on 16/6/22.
//  Copyright © 2016年 wujunyang. All rights reserved.
//

#import "jiaAppDelegate.h"
#import "GeTuiSdk.h"
#import "XAspect.h"
#import "jiaGTConfigManager.h"

NSString * const jiaGeTuiNotification = @"jiaGeTuiNotification";
NSString * const jiaReceiveRemoteNotification = @"jiaReceiveRemoteNotification";


#define AtAspect GeTuiAppDelegate

#define AtAspectOfClass jiaAppDelegate
@classPatchField(jiaAppDelegate)

@synthesizeNucleusPatch(Default, -, BOOL, application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions);
@synthesizeNucleusPatch(Default, -, void, application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken);
@synthesizeNucleusPatch(Default, -, void, application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error);
@synthesizeNucleusPatch(Default, -, void, application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings);
@synthesizeNucleusPatch(Default, -, void, application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler);
@synthesizeNucleusPatch(Default,-,void, dealloc);


AspectPatch(-, BOOL, application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions)
{
    //個推初始化
    [self initLoadGeTui:launchOptions];
    
    //註冊個推通知事件
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(geTuiMessageHandling:) name:jiaGeTuiNotification object:nil];
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(receiveRemoteMessageHandling:) name:jiaReceiveRemoteNotification object:nil];
    
    return XAMessageForward(application:application didFinishLaunchingWithOptions:launchOptions);
}

/** 遠程通知註冊成功委托 */
AspectPatch(-, void, application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken)
{
    NSString *myToken = [[deviceToken description] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]];
    myToken = [myToken stringByReplacingOccurrencesOfString:@" " withString:@""];
    
    [GeTuiSdk registerDeviceToken:myToken];
    
    NSLog(@"\n>>>[DeviceToken值]:%@\n\n", myToken);
    
    return XAMessageForward(application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken);
}

/** 遠程通知註冊失敗委托 */
AspectPatch(-, void, application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error){
    
    [GeTuiSdk registerDeviceToken:@""];
    
    NSLog(@"\n>>>[DeviceToken失敗]:%@\n\n", error.description);
    
    return XAMessageForward(application:application didFailToRegisterForRemoteNotificationsWithError:error);
}


#pragma mark - 用戶通知(推送)回調 _IOS 8.0以上使用

/** 已登記用戶通知 */
AspectPatch(-, void, application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings)
{
    // 註冊遠程通知(推送)
    [application registerForRemoteNotifications];
    
    return XAMessageForward(application:application didRegisterUserNotificationSettings:notificationSettings);
}


AspectPatch(-, void,application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler)
{
    
    //處理applicationIconBadgeNumber-1
    [self handlePushMessage:userInfo notification:nil];
    
    //除了個推還要處理走蘋果的信息放在body裡面
    if (userInfo) {
        NSString *payloadMsg = [userInfo objectForKey:@"payload"];
        NSString *message=[[[userInfo objectForKey:@"aps"]objectForKey:@"alert"]objectForKey:@"body"];
        
        NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:payloadMsg,@"payload",message,@"message",nil];
        //創建通知
        NSNotification *notification =[NSNotification notificationWithName:@"jiaReceiveRemoteNotification" object:nil userInfo:dict];
        //通過通知中心發送通知
        [[NSNotificationCenter defaultCenter] postNotification:notification];
    }
    // 處理APN
    //NSLog(@"\n>>>[Receive RemoteNotification - Background Fetch]:%@\n\n", userInfo);
    completionHandler(UIBackgroundFetchResultNewData);
    return XAMessageForward(application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler);
}

AspectPatch(-, void, dealloc)
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:jiaGeTuiNotification object:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:jiaReceiveRemoteNotification object:nil];
    XAMessageForwardDirectly(dealloc);
}


#pragma mark - GeTuiSdkDelegate

/** SDK啟動成功返回cid */
- (void)GeTuiSdkDidRegisterClient:(NSString *)clientId {
    // [4-EXT-1]: 個推SDK已註冊,返回clientId
    NSLog(@"\n>>>[個推Cid]:%@\n\n", clientId);
}

/** SDK遇到錯誤回調 */
- (void)GeTuiSdkDidOccurError:(NSError *)error {
    // [EXT]:個推錯誤報告,集成步驟發生的任何錯誤都在這裡通知,如果集成後,無法正常收到消息,查看這裡的通知。
    NSLog(@"\n>>>[GexinSdk error]:%@\n\n", [error localizedDescription]);
}



/** SDK收到sendMessage消息回調 */
- (void)GeTuiSdkDidSendMessage:(NSString *)messageId result:(int)result {
    // [4-EXT]:發送上行消息結果反饋
    NSString *msg = [NSString stringWithFormat:@"sendmessage=%@,result=%d", messageId, result];
    NSLog(@"\n>>>[GexinSdk DidSendMessage]:%@\n\n", msg);
}

/** SDK運行狀態通知 */
- (void)GeTuiSDkDidNotifySdkState:(SdkStatus)aStatus {
    // [EXT]:通知SDK運行狀態
    NSLog(@"\n>>>[GexinSdk SdkState]:%u\n\n", aStatus);
}

/** SDK設置推送模式回調 */
- (void)GeTuiSdkDidSetPushMode:(BOOL)isModeOff error:(NSError *)error {
    if (error) {
        NSLog(@"\n>>>[GexinSdk SetModeOff Error]:%@\n\n", [error localizedDescription]);
        return;
    }
    
    NSLog(@"\n>>>[GexinSdk SetModeOff]:%@\n\n", isModeOff ? @"開啟" : @"關閉");
}

// 處理推送消息
- (void)handlePushMessage:(NSDictionary *)dict notification:(UILocalNotification *)localNotification {
    if ([UIApplication sharedApplication].applicationIconBadgeNumber != 0) {
        if (localNotification) {
            [[UIApplication sharedApplication] cancelLocalNotification:localNotification];
        }
        [UIApplication sharedApplication].applicationIconBadgeNumber -= 1;
    }
    else {
        [[UIApplication sharedApplication] cancelAllLocalNotifications];
        [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
    }
}



/** SDK收到透傳消息回調 */
- (void)GeTuiSdkDidReceivePayload:(NSString *)payloadId andTaskId:(NSString *)taskId andMessageId:(NSString *)aMsgId andOffLine:(BOOL)offLine fromApplication:(NSString *)appId {
    
    [self handlePushMessage:nil notification:nil];
    // [4]: 收到個推消息
    NSData *payload = [GeTuiSdk retrivePayloadById:payloadId];
    NSString *payloadMsg = nil;
    if (payload) {
        payloadMsg = [[NSString alloc] initWithBytes:payload.bytes length:payload.length encoding:NSUTF8StringEncoding];
    }
    
    NSDictionary *dict =[[NSDictionary alloc] initWithObjectsAndKeys:aMsgId,@"aMsgId", [NSNumber numberWithBool:offLine],@"offLine",appId,@"appId",payloadMsg,@"payload",nil];
    //創建通知
    NSNotification *notification =[NSNotification notificationWithName:@"jiaGeTuiNotification" object:nil userInfo:dict];
    //通過通知中心發送通知
    [[NSNotificationCenter defaultCenter] postNotification:notification];
}


#pragma mark 自定義關於個推的內容

-(void)initLoadGeTui:(NSDictionary *)launchOptions
{
    // 通過 appId、 appKey 、appSecret 啟動SDK,註:該方法需要在主線程中調用
    [GeTuiSdk startSdkWithAppId:[jiaGTConfigManager sharedInstance].jiaGTAppId appKey:[jiaGTConfigManager sharedInstance].jiaGTAppKey appSecret:[jiaGTConfigManager sharedInstance].jiaGTAppSecret delegate:self];
    
    // 註冊APNS
    [self registerUserNotification];
    
    // 處理遠程通知啟動APP
    [self receiveNotificationByLaunchingOptions:launchOptions];
    
    //個推SDK支持當APP進入後臺後,個推是否運行。NO是不允許(為了讓個APP進入後端時就直接走蘋果推送)
    [GeTuiSdk runBackgroundEnable:NO];
}



#pragma mark - 用戶通知(推送) _自定義方法

/** 註冊用戶通知 */
- (void)registerUserNotification {
    
    /*
     註冊通知(推送)
     申請App需要接受來自服務商提供推送消息
     */
    
    // 判讀系統版本是否是“iOS 8.0”以上
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0 ||
        [UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
        
        // 定義用戶通知類型(Remote.遠程 - Badge.標記 Alert.提示 Sound.聲音)
        UIUserNotificationType types = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;
        
        // 定義用戶通知設置
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        
        // 註冊用戶通知 - 根據用戶通知設置
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
        [[UIApplication sharedApplication] registerForRemoteNotifications];
    } else { // iOS8.0 以前遠程推送設置方式
        // 定義遠程通知類型(Remote.遠程 - Badge.標記 Alert.提示 Sound.聲音)
        UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
        
        // 註冊遠程通知 -根據遠程通知類型
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
    }
}

/** 自定義:APP被“推送”啟動時處理推送消息處理(APP 未啟動--》啟動)*/
- (void)receiveNotificationByLaunchingOptions:(NSDictionary *)launchOptions {
    if (!launchOptions)
        return;
    
    /*
     通過“遠程推送”啟動APP
     UIApplicationLaunchOptionsRemoteNotificationKey 遠程推送Key

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在這個用數據說話的時代(靠臉吃飯的年代),沒有一個好的展現形態(沒有一張帥氣清秀的臉蛋),對於整個產品產生的影響,那簡直... ...
  • 通常,當客戶端請求一個包含React組件頁面的時候,服務端首先響應輸出這個頁面,客戶端和服務端有了第一次交互。然後,如果載入組件的過程需要向服務端發出Ajax請求等,客戶端和服務端又進行了一次交互,這樣,耗時相對較長。服務端是否可以在頁面初次載入時把所有方面渲染好再一次性響應給客戶端呢? 「Reac ...
  • 今天講課的時候,講到了html中的標簽的顯示模式,大致分為塊級標簽和行內標簽。那麼初學者在剛使用標簽的時候會發現有些屬性在一些標簽上不起作用,比如寬、高、水平居中等,其實這個屬性的使用只有在塊級標簽上使用才起作用。個人認為這個也是初學者非常容易忽略的地方,所以我就把它記下來! 比如會有一種情況,給p ...
  • JavaScript的作用域一直以來是前端開發中比較難以理解的知識點,對於JavaScript的作用域主要記住幾句話,走遍天下都不怕... 一、“JavaScript中無塊級作用域” 在Java或C#中存在塊級作用域,即:大括弧也是一個作用域。 public static void main () ...
  • SlidingMenu是一個第三方的開源的側滑控制項。是一種很好的交互邏輯。 有很多優秀的應用使用了SlidingMenu例如QQ和CSDN的安卓客戶端 其github主頁:https://github.com/jfeinstein10/SlidingMenu 在配置之前我們需要到其主頁上下載它的ZI ...
  • 博客: http://blog.csdn.net/lmj623565791 http://blog.csdn.net/u011733020 ...
  • 做出來效果:屏幕上的一塊UIView,點擊後能自由移動 ...
  • menu/share_action.xml MainActivity ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...