IOS 8.xでプッシュ通知を登録しようとした場合
application.registerForRemoteNotificationTypes(UIRemoteNotificationType.Alert | UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound)
次のようなエラーが表示されます。
registerForRemoteNotificationTypes: is not supported in iOS 8.0 and later.
それを行うための新しい方法は何ですか。 iOS 7.xでこのSwiftアプリを実行してもうまくいきます。
EDIT
IOS 7.xで、取得した条件付きコードを含めると(SystemVersion条件付きまたは#if __IPHONE_OS_VERSION_MAX_ALLOWED> = 80000)
dyld: Symbol not found: _OBJC_CLASS_$_UIUserNotificationSettings
あなたが説明したように、あなたはiOSの異なるバージョンに基づいて異なる方法を使う必要があるでしょう。あなたのチームがXcode 5(これはiOS 8セレクターを知らない)とXcode 6の両方を使用している場合は、次のように条件付きコンパイルを使用する必要があります。
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
// use registerUserNotificationSettings
} else {
// use registerForRemoteNotificationTypes:
}
#else
// use registerForRemoteNotificationTypes:
#endif
Xcode 6のみを使用している場合は、これだけを続けることができます。
if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {
// use registerUserNotificationSettings
} else {
// use registerForRemoteNotificationTypes:
}
その理由は、iOS 8では通知許可の取得方法が変更されたためです。UserNotification
は、リモートからでもローカルからでも、ユーザーに表示されるメッセージです。表示する権限を取得する必要があります。これはWWDC 2014ビデオ 「iOS通知の新機能」 で説明されています。
IOS 10未満の場合
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
//-- Set Notification
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
// iOS 8 Notifications
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
else
{
// iOS < 8 Notifications
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
//--- your custom code
return YES;
}
IOS10の場合
@ Prasathの答えを基にしています。これはSwiftで行う方法です。
if application.respondsToSelector("isRegisteredForRemoteNotifications")
{
// iOS 8 Notifications
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: (.Badge | .Sound | .Alert), categories: nil));
application.registerForRemoteNotifications()
}
else
{
// iOS < 8 Notifications
application.registerForRemoteNotificationTypes(.Badge | .Sound | .Alert)
}
iOS 8は、後方互換性のない方法で通知登録を変更しました。あなたがiOS 7と8をサポートする必要がある間(そして8 SDKで構築されたアプリは受け入れられない間)、あなたはあなたが必要とするセレクターをチェックし、実行中のバージョンに対してそれらを条件付きで呼び出すことができます。
これはUIApplicationのカテゴリで、Xcode 5とXcode 6の両方で機能する、クリーンなインターフェースの背後にこのロジックを隠します。
ヘッダ:
//Call these from your application code for both iOS 7 and 8
//put this in the public header
@interface UIApplication (RemoteNotifications)
- (BOOL)pushNotificationsEnabled;
- (void)registerForPushNotifications;
@end
実装:
//these declarations are to quiet the compiler when using 7.x SDK
//put this interface in the implementation file of this category, so they are
//not visible to any other code.
@interface NSObject (IOS8)
- (BOOL)isRegisteredForRemoteNotifications;
- (void)registerForRemoteNotifications;
+ (id)settingsForTypes:(NSUInteger)types categories:(NSSet*)categories;
- (void)registerUserNotificationSettings:(id)settings;
@end
@implementation UIApplication (RemoteNotifications)
- (BOOL)pushNotificationsEnabled
{
if ([self respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
return [self isRegisteredForRemoteNotifications];
}
else
{
return ([self enabledRemoteNotificationTypes] & UIRemoteNotificationTypeAlert);
}
}
- (void)registerForPushNotifications
{
if ([self respondsToSelector:@selector(registerForRemoteNotifications)])
{
[self registerForRemoteNotifications];
Class uiUserNotificationSettings = NSClassFromString(@"UIUserNotificationSettings");
//If you want to add other capabilities than just banner alerts, you'll need to grab their declarations from the iOS 8 SDK and define them in the same way.
NSUInteger UIUserNotificationTypeAlert = 1 << 2;
id settings = [uiUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert categories:[NSSet set]];
[self registerUserNotificationSettings:settings];
}
else
{
[self registerForRemoteNotificationTypes:UIRemoteNotificationTypeAlert];
}
}
@end
私たちがこのアプローチをとるのであれば、これが後方互換性を保つためのより良い方法だと私は思います。とてもわかりやすいです。
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)
{
[[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
else
{
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:
(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert)];
}
スイフトに傾いた人のために:
if let registration: AnyObject = NSClassFromString("UIUserNotificationSettings") { // iOS 8+
let notificationTypes: UIUserNotificationType = (.Alert | .Badge | .Sound)
let notificationSettings: UIUserNotificationSettings = UIUserNotificationSettings(forTypes: notificationTypes, categories: nil)
application.registerUserNotificationSettings(notificationSettings)
} else { // iOS 7
application.registerForRemoteNotificationTypes(.Alert | .Badge | .Sound)
}
私は "categories" NSSet変数が何に設定されるべきかわからなかったので、誰かが私に記入することができたら私は喜んでこの記事を編集します。ただし、次の場合はプッシュ通知ダイアログが表示されます。
[[UIApplication sharedApplication] registerForRemoteNotifications];
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert) categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
編集:私はこのコードで私の電話に送信するプッシュ通知を受け取ったので、categoriesパラメータが必要かどうかわかりません。
AnyObjectはidの精神的な後継者なので、AnyObjectに必要なメッセージを呼び出すことができます。これはidにメッセージを送信するのと同じことです。わかりました。しかし今、私たちはAnyObjectではすべてのメソッドはオプションであるという概念を付け加えています。
以上のことから、UIApplication.sharedApplication()をAnyObjectにキャストしてから、メソッドシグネチャと等しい変数を作成し、その変数をオプションのメソッドに設定してから、その変数をテストすることができれば幸いです。これはうまくいかなかったようです。私の推測では、iOS 8.0 SDKに対してコンパイルした場合、コンパイラはメソッドがであるべき場所を知っているので、これをすべてメモリルックアップまで最適化します。変数をテストしようとするまで、すべてうまくいきます。その時点でEXC_BAD_ACCESSが返されます。
しかし、私がすべてのメソッドがオプションであるという宝石を見つけた同じWWDCの話では、それらはオプションのメソッドを呼び出すためにOptional Chainingを使います - そしてこれはうまくいくようです。残念なのは、それが存在するかどうかを知るために実際にメソッドを呼び出そうとしなければならないことです。 UIUserNotificationSettingsオブジェクト。そのメソッドをnilで呼び出しても問題ありません。そのため、私には有効な解決策は次のようになります。
var ao: AnyObject = UIApplication.sharedApplication()
if let x:Void = ao.registerUserNotificationSettings?(nil) {
// It's iOS 8
var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
var settings = UIUserNotificationSettings(forTypes: types, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
} else {
// It's older
var types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Alert
UIApplication.sharedApplication().registerForRemoteNotificationTypes(types)
}
これに関連した多くの検索の後、重要な情報はこのWWDCトークから来ました https://developer.Apple.com/videos/wwdc/2014/#407 右「プロトコルのオプションのメソッド」に関するセクションの真ん中
Xcode 6.1 Betaでは、上記のコードは機能しません。以下のコードは機能します。
if UIApplication.sharedApplication().respondsToSelector("registerUserNotificationSettings:") {
// It's iOS 8
var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
var settings = UIUserNotificationSettings(forTypes: types, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
} else {
// It's older
var types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Alert
UIApplication.sharedApplication().registerForRemoteNotificationTypes(types)
}
IOS7 IOS8にサポートを追加したい場合は、このコードをプロジェクトに適用できます。
-(void) Subscribe {
NSLog(@"Registering for Push notifications...");
if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
[[UIApplication sharedApplication] registerForRemoteNotificationTypes: (UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)];
}
}
-(void)application:(UIApplication *)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
if (notificationSettings.types) {
NSLog(@"user allowed notifications");
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
NSLog(@"user did not allow notifications");
UIAlertView *alert =[[UIAlertView alloc]
initWithTitle:@"Please turn on Notification"
message:@"Go to Settings > Notifications > App.\n Switch on Sound, Badge & Alert"
delegate:self
cancelButtonTitle:@"Ok"
otherButtonTitles: nil];
[alert show];
// show alert here
}
}
スウィフト2.0
// Checking if app is running iOS 8
if application.respondsToSelector("isRegisteredForRemoteNotifications") {
print("registerApplicationForPushNotifications - iOS 8")
application.registerUserNotificationSettings(UIUserNotificationSettings(forTypes: [.Alert, .Badge, .Sound], categories: nil));
application.registerForRemoteNotifications()
} else {
// Register for Push Notifications before iOS 8
print("registerApplicationForPushNotifications - <iOS 8")
application.registerForRemoteNotificationTypes([UIRemoteNotificationType.Alert, UIRemoteNotificationType.Badge, UIRemoteNotificationType.Sound])
}
Xcode 6.1 Betaの後、以下のコードが機能するようになりましたが、Tom Sコードをわずかに編集して6.1 Betaの機能を停止させました(以前のBetaでも機能しました)。
if UIApplication.sharedApplication().respondsToSelector("registerUserNotificationSettings:") {
// It's iOS 8
var types = UIUserNotificationType.Badge | UIUserNotificationType.Sound | UIUserNotificationType.Alert
var settings = UIUserNotificationSettings(forTypes: types, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
} else {
// It's older
var types = UIRemoteNotificationType.Badge | UIRemoteNotificationType.Sound | UIRemoteNotificationType.Alert
UIApplication.sharedApplication().registerForRemoteNotificationTypes(types)
}
これが使えます
if ([application respondsToSelector:@selector(isRegisteredForRemoteNotifications)])
{
// for iOS 8
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
else
{
// for iOS < 8
[application registerForRemoteNotificationTypes:
(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound)];
}
// RESET THE BADGE COUNT
application.applicationIconBadgeNumber = 0;
必要なのがios 8コードだけであれば、これでうまくいくはずです。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
[application registerUserNotificationSettings: [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}
return YES;
}
iOS 8以降では
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert) categories:nil];
[application registerUserNotificationSettings:settings];
これは私がやっているよりきれいな方法であり、それはちょうど素晴らしい作品
if (floor(NSFoundationVersionNumber) < NSFoundationVersionNumber_iOS_8_0)
[[UIApplication sharedApplication] registerForRemoteNotificationTypes:UIRemoteNotificationTypeBadge|
UIRemoteNotificationTypeAlert| UIRemoteNotificationTypeSound];
else {
[application registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]];
[application registerForRemoteNotifications];
}