繁体   English   中英

使用iAd时,方向更改会导致iOS 7上的应用程序崩溃(无法识别的选择器发送到实例)

[英]Orientation change crashes app on iOS 7 when using iAd (unrecognized selector sent to instance)

集成iAd后,只要方向发生变化,我们的应用就会崩溃(即使我们仅将方向锁定为纵向)。 我们使用的是PhoneGap 3.2。 这是Xcode的输出:

2013-12-01 13:22:40.906 Wopple[4600:60b] -[CDViAd deviceOrientationChange:]: unrecognized selector sent to instance 0x166b07e0
2013-12-01 13:22:40.907 Wopple[4600:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CDViAd deviceOrientationChange:]: unrecognized selector sent to instance 0x166b07e0'
*** First throw call stack:
(0x2df75e83 0x382d66c7 0x2df797b7 0x2df780af 0x2dec6dc8 0x2df37e71 0x2deabab1 0x2e891ec5 0x306ffca5 0x306ff2e9 0x306fecfd 0x30764321 0x32bde76d 0x32bde357 0x2df40777 0x2df40713 0x2df3eedf 0x2dea9471 0x2dea9253 0x32bdd2eb 0x3075e845 0xe1e63 0x387cfab7)
libc++abi.dylib: terminating with uncaught exception of type NSException

这是我们的iAd代码:

//
//  CDViAd.m
//  Ad Plugin for PhoneGap
//
//  Created by shazron on 10-07-12.
//  Copyright 2010 Shazron Abdullah. All rights reserved.
//  Cordova v1.5.0 Support added 2012 @RandyMcMillan
//  Cordova v3.0.0 Support added 2013 @LimingXie

#import "CDViAd.h"
#import <Cordova/CDVDebug.h>


@interface CDViAd()

- (void) __prepare:(BOOL)atTop;
- (void) __showAd:(BOOL)show;

@end


@implementation CDViAd

@synthesize adView;
@synthesize bannerIsVisible, bannerIsInitialized, bannerAtTop, isLandscape;

#pragma mark -
#pragma mark Public Methods

- (CDVPlugin *)initWithWebView:(UIWebView *)theWebView {
  self = (CDViAd *)[super initWithWebView:theWebView];
  if (self) {
    // These notifications are required for re-placing the ad on orientation
    // changes. Start listening for notifications here since we need to
    // translate the Smart Banner constants according to the orientation.
    [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(deviceOrientationChange:)
               name:UIDeviceOrientationDidChangeNotification
             object:nil];
  }
  return self;
}

- (void) createBannerView:(CDVInvokedUrlCommand *)command
{
    CDVPluginResult *pluginResult;
    NSString *callbackId = command.callbackId;
    NSArray* arguments = command.arguments;

    NSUInteger argc = [arguments count];
    if (argc > 1) {
        return;
    }

    BOOL atTop = NO;
    NSString* atTopValue = [arguments objectAtIndex:0];
    if( atTopValue ) atTop = [atTopValue boolValue];
    [self __prepare:atTop];

    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
}

- (void) showAd:(CDVInvokedUrlCommand *)command
{
    CDVPluginResult *pluginResult;
    NSString *callbackId = command.callbackId;
    NSArray* arguments = command.arguments;

    NSUInteger argc = [arguments count];
    if (argc > 1) {
        return;
    }

    BOOL show = YES;
    NSString* showValue = [arguments objectAtIndex:0];
    if( showValue ) show = [showValue boolValue];
    [self __showAd:show];

    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:callbackId];
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    Class adBannerViewClass = NSClassFromString(@"ADBannerView");
    if (adBannerViewClass && self.adView) {

        if( UIInterfaceOrientationIsLandscape( toInterfaceOrientation ) ) {
            self.isLandscape = YES;
            self.adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
        } else {
            self.adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
        }

        [self resizeViews];
    }
}

- (void) resizeViews
{
    Class adBannerViewClass = NSClassFromString(@"ADBannerView");
    if (adBannerViewClass && self.adView) {

        CGRect webViewFrame = [super webView].frame;
        CGRect superViewFrame = [[super webView] superview].frame;
        CGRect adViewFrame = self.adView.frame;

        BOOL adIsShowing = [[[super webView] superview].subviews containsObject:self.adView];
        if (adIsShowing) {
            if (self.bannerAtTop) {
                webViewFrame.origin.y = adViewFrame.size.height;
            } else {
                webViewFrame.origin.y = 0;
                CGRect adViewFrame = self.adView.frame;
                CGRect superViewFrame = [[super webView] superview].frame;
                adViewFrame.origin.y = (self.isLandscape ? superViewFrame.size.width : superViewFrame.size.height) - adViewFrame.size.height;
                self.adView.frame = adViewFrame;
            }

            webViewFrame.size.height = self.isLandscape? (superViewFrame.size.width - adViewFrame.size.height) : (superViewFrame.size.height - adViewFrame.size.height);
        } else {
            webViewFrame.size = self.isLandscape? CGSizeMake(superViewFrame.size.height, superViewFrame.size.width) : superViewFrame.size;
            webViewFrame.origin = CGPointZero;
        }

        //[UIView beginAnimations:@"blah" context:NULL];
        //[UIView setAnimationDuration:0.5];
        //[self.adView setAlpha:1.0];
        //[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        [super webView].frame = webViewFrame;

        //[UIView commitAnimations];
    }
}

#pragma mark -
#pragma mark Private Methods

- (void) __prepare:(BOOL)atTop
{
    NSLog(@"CDViAd Prepare Ad, bannerAtTop: %d", atTop);

    Class adBannerViewClass = NSClassFromString(@"ADBannerView");
    if (adBannerViewClass && !self.adView) {
        self.adView = [[ADBannerView alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
        self.adView.requiredContentSizeIdentifiers = [NSSet setWithObjects: ADBannerContentSizeIdentifierPortrait, ADBannerContentSizeIdentifierLandscape, nil];        

        UIDeviceOrientation currentOrientation = [[UIDevice currentDevice] orientation];
        if( UIInterfaceOrientationIsLandscape( currentOrientation ) ) {
            self.isLandscape = YES;
            self.adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierLandscape;
        } else {
            self.isLandscape = NO;
            self.adView.currentContentSizeIdentifier = ADBannerContentSizeIdentifierPortrait;
        }

        self.adView.delegate = self;
        self.adView.backgroundColor = [UIColor blackColor];
        //[self.webView.superview addSubview:self.adView];

        self.webView.superview.backgroundColor = [UIColor blackColor];

        self.bannerAtTop = atTop;
        self.bannerIsVisible = NO;
        self.bannerIsInitialized = YES;

        [self resizeViews];
    }
}

- (void) __showAd:(BOOL)show
{
    NSLog(@"CDViAd Show Ad: %d", show);

    if (!self.bannerIsInitialized){
        [self __prepare:NO];
    }

    if (!(NSClassFromString(@"ADBannerView") && self.adView)) { // ad classes not available
        return;
    }

    if (show == self.bannerIsVisible) { // same state, nothing to do
        return;
    }

    if (show) {
        //[UIView beginAnimations:@"blah" context:NULL];
        //[UIView setAnimationDuration:0.5];
        //[self.adView setAlpha:1.0];
        //[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        [[[super webView] superview] addSubview:self.adView];
        [[[super webView] superview] bringSubviewToFront:self.adView];
        [self resizeViews];

        //[UIView commitAnimations];

        self.bannerIsVisible = YES;
    } else {
        //[UIView beginAnimations:@"blah" context:NULL];
        //[UIView setAnimationDuration:0.5];
        //[self.adView setAlpha:0.0];
        //[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];

        [self.adView removeFromSuperview];
        [self resizeViews];

        //[UIView commitAnimations];

        self.bannerIsVisible = NO;
    }

}

#pragma mark -
#pragma ADBannerViewDelegate

- (BOOL)bannerViewActionShouldBegin:(ADBannerView *)banner willLeaveApplication:(BOOL)willLeave
{
    NSLog(@"Banner view begining action");

    [self writeJavascript:@"cordova.fireDocumentEvent('onClickAd');"];
    if (!willLeave) {

    }
    return YES;
}

- (void)bannerViewActionDidFinish:(ADBannerView *)banner
{
    NSLog(@"Banner view finished action");
}

- (void)bannerViewDidLoadAd:(ADBannerView *)banner
{
    NSLog(@"Banner Ad loaded");

    Class adBannerViewClass = NSClassFromString(@"ADBannerView");
    if (adBannerViewClass) {
        if (!self.bannerIsVisible) {
            [self __showAd:YES];
        }

        [self writeJavascript:@"cordova.fireDocumentEvent('onReceiveAd');"];
    }
}

- (void)bannerView:(ADBannerView *)banner didFailToReceiveAdWithError:(NSError*)error
{
    NSLog(@"Banner failed to load Ad");

    Class adBannerViewClass = NSClassFromString(@"ADBannerView");
    if (adBannerViewClass) {
        //if ( self.bannerIsVisible ) {
        //  [self __showAd:NO];
        //}

        NSString *jsString =
            @"cordova.fireDocumentEvent('onFailedToReceiveAd',"
            @"{ 'error': '%@' });";
        [self writeJavascript:[NSString stringWithFormat:jsString, [error description]]];
    }
}

- (void)dealloc {
    [[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter]
        removeObserver:self
        name:UIDeviceOrientationDidChangeNotification
        object:nil];

    self.adView.delegate = nil;
    self.adView = nil;
}

@end

Rich Tolley建议的编辑代码:

- (CDVPlugin *)initWithWebView:(UIWebView *)theWebView {
  self = (CDViAd *)[super initWithWebView:theWebView];
  if (self) {
    // These notifications are required for re-placing the ad on orientation
    // changes. Start listening for notifications here since we need to
    // translate the Smart Banner constants according to the orientation.
    /*[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter]
        addObserver:self
           selector:@selector(deviceOrientationChange:)
               name:UIDeviceOrientationDidChangeNotification
             object:nil];*/
  }
  return self;
}

- (void)dealloc {
    /*[[UIDevice currentDevice] endGeneratingDeviceOrientationNotifications];
    [[NSNotificationCenter defaultCenter]
        removeObserver:self
        name:UIDeviceOrientationDidChangeNotification
        object:nil];*/

    self.adView.delegate = nil;
    self.adView = nil;
}

您收到通知是因为它们是设备方向更新-而不是界面方向更新。 即使UI不会更改方向,设备也可以更改方向,因此您仍然可以获得更新。

崩溃是因为代码缺少通知方法:

- (void)deviceOrientationChange:(NSNotification *)notification

查看CDViAid.m的源代码,它订阅了一个通知,但没有声明处理该通知的方法:

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(deviceOrientationChange:)
           name:UIDeviceOrientationDidChangeNotification
         object:nil];

(在超类上也没有任何处理)

对此有一个错误报告: https : //github.com/floatinghotpot/cordova-plugin-iad/issues/1 ,以及一个建议的解决方案,该解决方案似乎复制了willRotateToInterfaceOrientation

您可以只删除通知-init-dealloc添加和删​​除代码-因为它没有方法可以调用,所以它什么也不能做。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM