3

我正在为 Adob​​e AIR 开发 iOS 原生扩展,它将获取推送通知的设备令牌。不幸的是,我不是那种非常喜欢 Objective-C 的程序员,而且我不确定我正在使用的代码是否有问题。它编译没有问题,我可以将扩展与 AIR 一起使用,但看起来注册通知既不会返回正面效果也不会返回负面效果。因此,我要做的是在从 AIR 调用 RegisterDevice 函数时注册通知,如果它确实注册,则将设备令牌存储在 deviceTokenString 中,如果它没有注册并返回错误,我将错误存储在此字符串中. 当调用 GetToken 函数时,我将 deviceTokenString 返回给 AIR,因此它要么是令牌,要么是错误。在 AIR 应用程序中,我首先通过单击按钮启动 RegisterDevice 函数,然后启动 GetToken 函数。不幸的是,我既没有得到令牌也没有得到错误(也没有出现要求许可的弹出窗口)。我也试图将注册部分放入 didFinishLaunchingWithOptions 但看起来 didFinishLaunchingWithOptions 从未启动。如果你们可以看看代码是否可以,我将非常感激。或者,也许您有任何想法还有什么可能是错的?我在配置门户中启用了推送 SSL 证书。这是我正在使用的代码 如果你们可以看看代码是否可以,我将非常感激。或者,也许您有任何想法还有什么可能是错的?我在配置门户中启用了推送 SSL 证书。这是我正在使用的代码 如果你们可以看看代码是否可以,我将非常感激。或者,也许您有任何想法还有什么可能是错的?我在配置门户中启用了推送 SSL 证书。这是我正在使用的代码

“NativePush.m”:

#import "UIKit/UIKit.h"
#import "include/FlashRuntimeExtensions.h"

@implementation NativePush

@synthesize tokenString = _tokenString;

NSString *deviceTokenString = @"";

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}

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

- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken 
{ 
    NSString *str = 
    [NSString stringWithFormat:@"%@",deviceToken];
    deviceTokenString = str;
}

- (void)application:(UIApplication *)app didFailToRegisterForRemoteNotificationsWithError:(NSError *)err 
{ 
    NSString *str = [NSString stringWithFormat: @"Error: %@", err];   
    deviceTokenString = str;
}

void ContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx,
                        uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet) {
    *numFunctionsToTest = 2;
    FRENamedFunction* func = (FRENamedFunction*)malloc(sizeof(FRENamedFunction)*2);
    func[0].name = (const uint8_t*)"RegisterDevice";
    func[0].functionData = NULL;
    func[0].function = &RegisterDevice;

    func[1].name = (const uint8_t*)"GetToken";
    func[1].functionData = NULL;
    func[1].function = &GetToken;

    *functionsToSet = func;
}

void ContextFinalizer(FREContext ctx) {
    return;
}

void ExtInitializer(void** extDataToSet, FREContextInitializer* ctxInitializerToSet,
                    FREContextFinalizer* ctxFinalizerToSet) {
    *extDataToSet = NULL;
    *ctxInitializerToSet = &ContextInitializer;
    *ctxFinalizerToSet = &ContextFinalizer;
}

void ExtFinalizer(void* extData) {
    return;
}

FREObject RegisterDevice(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {

    [[UIApplication sharedApplication] 
     registerForRemoteNotificationTypes:
     (UIRemoteNotificationTypeAlert | 
      UIRemoteNotificationTypeBadge | 
      UIRemoteNotificationTypeSound)];

    return NULL;
}

FREObject GetToken(FREContext ctx, void* funcData, uint32_t argc, FREObject argv[]) {

    NSString* tokenS =  deviceTokenString;

    char* tokenChar = [tokenS UTF8String];
    FREObject tokenObject = NULL;

    FRENewObjectFromUTF8( strlen(tokenChar)+1 , (const uint8_t*)tokenChar, &tokenObject);

    return tokenObject;

}

@end

和头文件“NativePush.h”:

import "Foundation/Foundation.h"
import "include/FlashRuntimeExtensions.h"

@interface NativePush : NSObject
@property (nonatomic, retain) NSString* tokenString;

FREObject RegisterDevice(
                        FREContext ctx,
                        void* funcData,
                        uint32_t argc,
                        FREObject arg[]
                        );
FREObject GetToken(
                        FREContext ctx,
                        void* funcData,
                        uint32_t argc,
                        FREObject arg[]
                        );
void ContextInitializer(
                        void* extData,
                        const uint8_t* ctxType,
                        FREContext ctx,
                        uint32_t* numFunctionsToTest,
                        const FRENamedFunction** functionsToSet
                        );
void ContextFinalizer(FREContext ctx);
void ExtInitializer(
                    void** extDataToSet,
                    FREContextInitializer* ctxInitializerToSet,
                    FREContextFinalizer* ctxFinalizerToSet
                    );
void ExtFinalizer(void* extData);
@end
4

2 回答 2

4

好的,

把头发扯掉3天后,我想通了。我不设置委托,因为这会破坏所有 Adob​​e 的东西。我创建了现有委托的自定义子类并覆盖了与 APNS 相关的委托函数。我的代码如下。

//empty delegate functions, stubbed signature is so we can find this method in the delegate
//and override it with our custom implementation
- (void)application:(UIApplication*)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken{}

    - (void)application:(UIApplication*)application didFailToRegisterForRemoteNotificationsWithError:(NSError*)error{}


   //custom implementations of empty signatures above
void didRegisterForRemoteNotificationsWithDeviceToken(id self, SEL _cmd, UIApplication* application, NSData* deviceToken)
{
NSLog(@"My token is: %@", deviceToken);
}


 void didFailToRegisterForRemoteNotificationsWithError(id self, SEL _cmd, UIApplication* application, NSError* error)
{
NSLog(@"Failed to get token, error: %@", error);
}





// ContextInitializer()
//
// The context initializer is called when the runtime creates the extension context instance.
void PushContextInitializer(void* extData, const uint8_t* ctxType, FREContext ctx, 
                    uint32_t* numFunctionsToTest, const FRENamedFunction** functionsToSet) 
{

//injects our modified delegate functions into the sharedApplication delegate

id delegate = [[UIApplication sharedApplication] delegate];

Class objectClass = object_getClass(delegate);

NSString *newClassName = [NSString stringWithFormat:@"Custom_%@", NSStringFromClass(objectClass)];
Class modDelegate = NSClassFromString(newClassName);
if (modDelegate == nil) {
    // this class doesn't exist; create it
    // allocate a new class
    modDelegate = objc_allocateClassPair(objectClass, [newClassName UTF8String], 0);

    SEL selectorToOverride1 = @selector(application:didRegisterForRemoteNotificationsWithDeviceToken:);

    SEL selectorToOverride2 = @selector(application:didFailToRegisterForRemoteNotificationsWithError:);

    // get the info on the method we're going to override
    Method m1 = class_getInstanceMethod([jreporterNativePush class], selectorToOverride1);
    Method m2 = class_getInstanceMethod([jreporterNativePush class], selectorToOverride2);

    // add the method to the new class
    class_addMethod(modDelegate, selectorToOverride1, (IMP)didRegisterForRemoteNotificationsWithDeviceToken, method_getTypeEncoding(m1));

    class_addMethod(modDelegate, selectorToOverride2, (IMP)didFailToRegisterForRemoteNotificationsWithError, method_getTypeEncoding(m2));

    // register the new class with the runtime
    objc_registerClassPair(modDelegate);
}
// change the class of the object
object_setClass(delegate, modDelegate);


NSLog(@"completed crazy swap w/o bombing  w00t");

///////// end of delegate injection / modification code



*numFunctionsToTest = 1;

FRENamedFunction* func = (FRENamedFunction*) malloc(sizeof(FRENamedFunction) * 1);

func[0].name = (const uint8_t*) "registerPush";
func[0].functionData = NULL;
func[0].function = &registerPush;

*functionsToSet = func;

}

于 2012-02-29T12:51:11.700 回答
2

问题是,一旦向 apns 注册,您就不会告诉您的应用程序要调用哪个函数。为此,您必须创建并设置一个所谓的委托 - 阅读https://developer.apple.com/library/ios/#documentation/General/Conceptual/CocoaEncyclopedia/DelegatesandDataSources/DelegatesandDataSources。html#//apple_ref/doc/uid/TP40010810-CH11-SW1

您可以通过实现 UIApplicationDelegate 协议来创建所需的委托。协议与 java 中的接口概念非常相似 - 阅读https://developer.apple.com/library/ios/#referencelibrary/GettingStart ed/Learning_Objective-C_A_Primer/_index.html

所以你基本上将通过指定一个头文件和实现来创建一个单独的类,并将这个类的一个实例设置为你的 uiapplicationdelegate。现在,您不必要地围绕静态代码包装一个类并添加与应在委托中调用的函数同名的函数,但您没有告诉应用程序您的委托。设置委托的好地方是您的 nativeextension 的 contextinitializer 函数,您可以在其中调用如下内容:

delegate = [[UINativePushAppDelegate alloc] init];
[[UIApplication sharedApplication] setDelegate:delegate];  // assuming there is a class, called uinativepushappdelegate

现在,一旦您注册了 apns,应用程序将调用此实例的 didRegisterForRemoteNotificationsWithDeviceToken 方法。

于 2012-02-09T12:48:43.070 回答