Explaining the issue :
I've now tried getting firebase_messaging to work for almost a week.
I successfully set up an legacy Xcode APNS app, which worked after generating all new certificates, etc.
But with firebase_messaging I get no notifications at all.
I even gone so far as recreating a new flutter, firebase and appstoreconnect projects/apps.
But I got no notifications at all from firebase, either implemented in native Xcode or flutter.
If I subscribe to a topic which doesn't exist yet, it's being created; Notifications on Android and Analytics and InAppMessaging on iOS and Android are working fine, so definitely something is working.
What I've tried so far :
The official example projects for firebase_messaging on native Xcode and Flutter/Dart
Recreating all licenses/projects
Sending messages by topic (which I planned to do anyway)
applying patches/fixes/tips from GitHub/stackoverflow.
Code snippets to recreate the configuration :
Steps to recreate could be just downloading the Firebase Messaging example projects or following the official docs of setting up Firebase Messaging for native Xcode or Flutter. Basic steps to recreate examples listed here :
Implemented plugins (all newest versions) :
firebase_messaging
firebase_core
firebase_analytics
Flutter/Dart (main.dart):
void firebaseCloudMessaging_Listeners() {
if (Platform.isIOS) iOS_Permission();
firebaseMessaging.getToken().then((token){
print(token);
});
firebaseMessaging.configure(
onMessage: (Map<String, dynamic> message) async {
print('on message $message');
},
onResume: (Map<String, dynamic> message) async {
print('on resume $message');
},
onLaunch: (Map<String, dynamic> message) async {
print('on launch $message');
},
);
}
void iOS_Permission() {
firebaseMessaging.requestNotificationPermissions(
IosNotificationSettings(sound: true, badge: true, alert: true)
);
firebaseMessaging.onIosSettingsRegistered
.listen((IosNotificationSettings settings)
{
print("Settings registered: $settings");
});
}
void subscribeToFB() {
firebaseMessaging.subscribeToTopic('-------------Sandbox');
print("--- SUBSCRIBED ---");
}
void unsubscribeFromFB() {
firebaseMessaging.unsubscribeFromTopic('-------------Sandbox');
print("--- UNSUBSCRIBED ---");
}
Implemented Pods (all newest versions) :
pod 'Firebase/Messaging'
pod 'Firebase/Analytics'
Native Xcode (AppDelegate.h):
#import "AppDelegate.h"
#import UserNotifications;
#interface AppDelegate () <UNUserNotificationCenterDelegate>
#end
#implementation AppDelegate
NSString *const kGCMMessageIDKey = #"gcm.message_id";
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// [START configure_firebase]
[FIRApp configure];
// [END configure_firebase]
// [START set_messaging_delegate]
[FIRMessaging messaging].delegate = self;
// [END set_messaging_delegate]
// Register for remote notifications. This shows a permission dialog on first run, to
// show the dialog at a more appropriate time move this registration accordingly.
// [START register_for_notifications]
if ([UNUserNotificationCenter class] != nil) {
// iOS 10 or later
// For iOS 10 display notification (sent via APNS)
[UNUserNotificationCenter currentNotificationCenter].delegate = self;
UNAuthorizationOptions authOptions = UNAuthorizationOptionAlert |
UNAuthorizationOptionSound | UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
// ...
}];
} else {
// iOS 10 notifications aren't available; fall back to iOS 8-9 notifications.
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[application registerUserNotificationSettings:settings];
}
[application registerForRemoteNotifications];
// [END register_for_notifications]
return YES;
}
// [START receive_message]
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// Print message ID.
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
}
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
// If you are receiving a notification message while your app is in the background,
// this callback will not be fired till the user taps on the notification launching the application.
// TODO: Handle data of notification
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// Print message ID.
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
completionHandler(UIBackgroundFetchResultNewData);
}
// [END receive_message]
// [START ios_10_message_handling]
// Receive displayed notifications for iOS 10 devices.
// Handle incoming notification messages while app is in the foreground.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
willPresentNotification:(UNNotification *)notification
withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler {
NSDictionary *userInfo = notification.request.content.userInfo;
// With swizzling disabled you must let Messaging know about the message, for Analytics
// [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
// Print message ID.
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
// Change this to your preferred presentation option
completionHandler(UNNotificationPresentationOptionNone);
}
// Handle notification messages after display notification is tapped by the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
didReceiveNotificationResponse:(UNNotificationResponse *)response
withCompletionHandler:(void(^)(void))completionHandler {
NSDictionary *userInfo = response.notification.request.content.userInfo;
if (userInfo[kGCMMessageIDKey]) {
NSLog(#"Message ID: %#", userInfo[kGCMMessageIDKey]);
}
// Print full message.
NSLog(#"%#", userInfo);
completionHandler();
}
// [END ios_10_message_handling]
// [START refresh_token]
- (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
NSLog(#"FCM registration token: %#", fcmToken);
// Notify about received token.
NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:#"token"];
[[NSNotificationCenter defaultCenter] postNotificationName:
#"FCMToken" object:nil userInfo:dataDict];
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}
// [END refresh_token]
// [START ios_10_data_message]
// Receive data messages on iOS 10+ directly from FCM (bypassing APNs) when the app is in the foreground.
// To enable direct data messages, you can set [Messaging messaging].shouldEstablishDirectChannel to YES.
- (void)messaging:(FIRMessaging *)messaging didReceiveMessage:(FIRMessagingRemoteMessage *)remoteMessage {
NSLog(#"Received data message: %#", remoteMessage.appData);
}
// [END ios_10_data_message]
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSLog(#"Unable to register for remote notifications: %#", error);
}
// This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
// If swizzling is disabled then this function must be implemented so that the APNs device token can be paired to
// the FCM registration token.
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
NSLog(#"APNs device token retrieved: %#", deviceToken);
// With swizzling disabled you must set the APNs device token here.
// [FIRMessaging messaging].APNSToken = deviceToken;
}
#end
The IDEs (Xcode/VS Code # macOS HS) do not return any errors; also no errors in debug log. The app reports to be working fine but the messages just don't come through.
Can someone please help me with this? Thanks!
The fix was to just remove the suggested .p8 Key File (from Firebase Console > Project Settings > Cloud Messaging) and instead put in the APNS Development and Release Certificates.
Related
NSWorkspace has the method open(_:withAppBundleIdentifier: [...] ):
Opens one or more files from an array of URLs.
func open(_ urls: [URL],
withAppBundleIdentifier bundleIdentifier: String?,
options: NSWorkspace.LaunchOptions = [],
additionalEventParamDescriptor descriptor: NSAppleEventDescriptor?,
launchIdentifiers identifiers:) -> Bool
The NSApplicationDelegate of the app you want to open has corresponding methods that are called to open the URL(s) you provide:
func application(_ sender: NSApplication, openFile filename: String) -> Bool
func application(_ sender: NSApplication, openFiles filenames: [String])
Back to open(_:withAppBundleIdentifier: [...]), that method has an NSAppleEventDescriptor parameter:
additionalEventParamDescriptor descriptor: NSAppleEventDescriptor?
Additional options specified in an AppleEvent-style descriptor. For example, you could use this parameter to specify additional documents to open when the app is launched.
I would like to send additional information to the app that will open the files.
This would be used similarly to the userInfo dictionary on a notification.
I've constructed a NSAppleEventDescriptor object to represent this information. I can set this event descriptor in the NSWorkspace open( ... ) function.
But how do I receive this event descriptor in Application Delegate of the target app?
The application(_: openFile:) functions have no parameters for the event descriptors or any other "userInfo"-type additional information.
Code
Based on answers and other questions, I settled on the solution below. I am now getting a triggered handler for Apple Events. But the Apple Event that I am setting on the NSWorkspace function is not the one that is received in the handler! How do I get my Apple Event instead?
Send
let appleEvent = NSAppleEventDescriptor(eventClass: AEEventClass(kCoreEventClass),
eventID: AEEventID(kAEOpenDocuments),
targetDescriptor: nil,
returnID: AEReturnID(kAutoGenerateReturnID),
transactionID: AETransactionID(kAnyTransactionID))
appleEvent.setDescriptor(NSAppleEventDescriptor(string: "THIS IS A TEST"), forKeyword: keyDirectObject)
let didOpen = AppKit.NSWorkspace.shared.open([URL(fileURLWithPath: "/path/image.png")],
withAppBundleIdentifier: bundleID,
options: [.withErrorPresentation],
additionalEventParamDescriptor: appleEvent,
launchIdentifiers: nil)
Sent Apple Event:
<NSAppleEventDescriptor: 'aevt'\'odoc'{ '----':'utxt'("THIS IS A TEST") }>
Receive
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
NSAppleEventManager.shared().setEventHandler(self,
andSelector: #selector(handle(event:replyEvent:)),
forEventClass: AEEventClass(kCoreEventClass),
andEventID: AEEventID(kAEOpenDocuments))
}
#objc func handle(event: NSAppleEventDescriptor?, replyEvent: NSAppleEventDescriptor?) {
guard let event = event,
event.eventClass == AEEventClass(kCoreEventClass) && event.eventID == AEEventID(kAEOpenDocuments) else {
return
}
guard let additionalEventParamDescriptor = event.paramDescriptor(forKeyword: keyAEPropData) else {
return
}
guard let directObject = additionalEventParamDescriptor.paramDescriptor(forKeyword: keyDirectObject) else {
return
}
print(directObject)
}
}
Received Apple Event:
<NSAppleEventDescriptor: 'aevt'\'odoc'{ '----':[ 'bmrk'(888/$626F6F6B7803000000000 [....] 00000AC01000000000000...$) ] }>
kAEOpenDocuments events approach
- (void)applicationWillFinishLaunching:(NSNotification *)notification {
[[NSAppleEventManager sharedAppleEventManager] setEventHandler:self andSelector:#selector(handleAppleEvent:withReplyEvent:) forEventClass:kCoreEventClass andEventID:kAEOpenDocuments];
}
- (void)handleAppleEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
}
-[NSWorkspace openURLs: ...] generates an kAEOpenDocuments event that contains the URLs as sandbox save bookmark data. (See +[NSURL URLByResolvingBookmarkData: options: relativeToURL: bookmarkDataIsStale: error:]).
The additionalEventParamDescriptor:
When creating the additionalEventParamDescriptor with kAEOpenDocuments with a custom parameters, this event seems to get merged with the underlaying kAEOpenDocuments event from -[NSWorkspace openURLs: ...].
NSAppleEventDescriptor *targetDescriptor = nil;
NSAppleEventDescriptor *appleEvent = nil;
targetDescriptor = [NSAppleEventDescriptor descriptorWithDescriptorType:typeApplicationBundleID
data:targetBundleID];
appleEvent = [NSAppleEventDescriptor appleEventWithEventClass:kCoreEventClass
eventID:kAEOpenDocuments
targetDescriptor:targetDescriptor
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
[appleEvent setParamDescriptor:[NSAppleEventDescriptor descriptorWithString:#"You're so good looking"]
forKeyword:'urln'];
[[NSWorkspace sharedWorkspace] openURLs:#[ [[NSBundle mainBundle] resourceURL] ]
withAppBundleIdentifier:bundleIdentifier
options:NSWorkspaceLaunchNewInstance
additionalEventParamDescriptor:appleEvent
launchIdentifiers:NULL];
Sample lldb output:
NSAppleEventDescriptor: 'aevt'\'odoc'{ ~'prdt':'aevt'\'odoc'{
'urln':'utxt'("You're so good looking") }, '----':[
'bmrk'(1432/$626F6F6B980 ...) }
Note: When setting the NSAppleEventManager for kAEOpenDocuments this overwrites AppKits build-in functionality of the application:openFile: or application:openFiles: methods. The custom event handler needs to implement all that.
custom events approach
Based on my findings sending a custom event class with a custom event ID does not trigger the event handler. ¯_(ツ)_/¯
System call interface active hanging call proxy method : provider(provider: CXProvider, performEndCallAction action: CXEndCallAction),but the system call interface passively hangs how to realize the system interface call end?
(void)performEndCallActionWithUUID:(NSUUID *)uuid {
if (uuid == nil) {
return;
}
CXEndCallAction *endCallAction = [[CXEndCallAction alloc] initWithCallUUID:uuid];
CXTransaction *transaction = [[CXTransaction alloc] initWithAction:endCallAction];
[self.callKitCallController requestTransaction:transaction completion:^(NSError *error) {
if (error) {
NSLog(#"EndCallAction transaction request failed: %#", [error localizedDescription]);
}
else {
[endCallAction fail];
NSLog(#"EndCallAction transaction request successful");
}
}];
}
Call this function when you end the call
I am using the following CKNotification Info and this seems to work fine:
CKNotificationInfo *note = [[CKNotificationInfo alloc] init];
note.alertBody = #"Something Happened";
note.shouldBadge = NO;
note.shouldSendContentAvailable = NO;
When something changes on an iOS device, my Mac app receives a Push notification based on a subscription with this notification. However, didReceiveRemoteNotification is never called so I can't process the event. I need to be able to refresh and fetch new changes. How do I do that?
Calling registerForRemoteNotificationTypes: and implementing didRegisterForRemoteNotificationsWithDeviceToken:
should be enough code, and the App ID should include the Push Notifications service.
I'm using CloudKit in a cross-platform (iOS/OS X) app to synchronize favorites between devices like so:
// OS X specific code
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
[NSApp registerForRemoteNotificationTypes:NSRemoteNotificationTypeNone];// silent push notification!
}
- (void)application:(NSApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
[self.favCon handleCloudKitNotificationWithUserInfo:userInfo];
}
Note the usage of NSRemoteNotificationTypeNone which means silent push notification! This is how I set up CloudKit in the FavController class:
- (void)getOrCreateFavZoneWithCompletionHandler:(successCompletionHandler)handler {
// check if FavZone exists op
__block int createZone = 0;
CKFetchRecordZonesOperation *fetchRecZonesOp = [[CKFetchRecordZonesOperation alloc] initWithRecordZoneIDs:#[[FavController favRecordZoneID]]];
CKModifyRecordZonesOperation *saveRecZoneOp = [[CKModifyRecordZonesOperation alloc] initWithRecordZonesToSave:nil recordZoneIDsToDelete:nil];
fetchRecZonesOp.fetchRecordZonesCompletionBlock = ^(NSDictionary *recordZonesByZoneID, NSError *operationError) {
if (recordZonesByZoneID.count == 0) {// zone doesn't exist
createZone = 1;
CKRecordZone *favZone = [[CKRecordZone alloc] initWithZoneName:UTXAFavZoneName];
saveRecZoneOp.recordZonesToSave = #[favZone];
NSLog(#"Creating new Zone %#", favZone.zoneID.zoneName);
} else {
NSLog(#"Zone %# already exists.", [FavController favRecordZoneID].zoneName);
}
};
// create FavZone op
saveRecZoneOp.modifyRecordZonesCompletionBlock = ^(NSArray *savedRecordZones, NSArray *deletedRecordZoneIDs, NSError *operationError) {
[self successCompletionHandler:(savedRecordZones.count == createZone) error:operationError informDelegate:YES handler:handler];
};
[saveRecZoneOp addDependency:fetchRecZonesOp];
[[FavController favDatabase] addOperation:fetchRecZonesOp];
[[FavController favDatabase] addOperation:saveRecZoneOp];
}
- (void)subscribeToFavChanges:(successCompletionHandler)handler {
// get current subscription
[[FavController favDatabase] fetchSubscriptionWithID:UTXAFavConCKSubscriptionID completionHandler:^(CKSubscription *subscription, NSError *error) {
if (subscription) {
NSLog(#"using existing subscription: %#", subscription);
[self successCompletionHandler:YES error:nil informDelegate:NO handler:handler];
} else {
CKSubscription *sub = [[CKSubscription alloc] initWithZoneID:[FavController favRecordZoneID]
subscriptionID:UTXAFavConCKSubscriptionID
options:0];// "You must specify 0 for this parameter. Zone subscriptions currently do not support any options."
[[FavController favDatabase] saveSubscription:sub completionHandler:^(CKSubscription *subscription, NSError *error) {
NSLog(#"created new subscription: %# %#", subscription, error);
[self successCompletionHandler:(error == nil) error:error informDelegate:YES handler:handler];
}];
}
}];
}
As soon as I add or remove a record on one device, I'll get a notification on all other device, which I handle like so in the FavController class:
/// #abstract Handle push notifications sent by iCloud.
/// #discussion App delegates call this method when they receive a push notification through didReceiveRemoteNotification.
/// Currently, only airport favorites produce a PN, it is of type CKNotificationTypeRecordZone.
/// #param userInfo The userInfo dict tied to each push notification.
- (void)handleCloudKitNotificationWithUserInfo:(NSDictionary *)userInfo {
[self recursivelyCheckForPreviousCloudKitNotifications];
}
- (void)recursivelyCheckForPreviousCloudKitNotifications {
CKFetchNotificationChangesOperation *fetchOp = [[CKFetchNotificationChangesOperation alloc] initWithPreviousServerChangeToken:_defCon.notificationChangeToken];
__weak CKFetchNotificationChangesOperation *weakOp = fetchOp;
fetchOp.notificationChangedBlock = ^(CKNotification *notification) {
[self handleNotification:notification];
};
fetchOp.fetchNotificationChangesCompletionBlock = ^( CKServerChangeToken *serverChangeToken, NSError *operationError) {
NSLog(#"new notification change token: %#", serverChangeToken);
_defCon.notificationChangeToken = serverChangeToken;
if (weakOp.moreComing) {
NSLog(#"more coming!!");
[self recursivelyCheckForPreviousCloudKitNotifications];
} else {
NSLog(#"done handling notification changes.");
}
};
[[FavController favContainer] addOperation:fetchOp];
}
- (void)handleNotification:(CKNotification *)notification {// withCompletionHandler:(successCompletionHandler)handler {
if (notification.notificationType == CKNotificationTypeRecordZone) {// make sure we handle only zone changes
CKRecordZoneNotification *noti = (CKRecordZoneNotification *)notification;
if ([noti.recordZoneID.zoneName isEqualToString:[FavController favRecordZoneID].zoneName]) {
// received an update for the fav zone
[self queuedFavUpdateFromCloud];
} else {
// received an update for an unknown zone
NSLog(#"WARNING: received an update for an unknown zone: %#", noti.recordZoneID.zoneName);
}
} else {
NSLog(#"WARNING: received unknown notification: %#", notification);
}
}
Okay I've finally figured it out. If you use a CKNotificationInfo for your alerts, didReceiveRemoteNotification will NOT be called on the Mac until and unless you set CKNotificationInfo.soundName to an empty string! This looks like a bug only in OS X (10.10 & 10.11 so far) but can be worked around by this simple change.
Coded in Swift I implemented after the Tutorial.
DBAccountManager is setup in AppDelegate on applicationDidFinishLaunching.
Later, when the user activates dropbox support in my application I'm trying to link the account.
The Window Panel is displayed and my application is waiting for the callback.
Sometimes I do not get a linked account, even the user logs in and accepts.
The Log says
"[ERROR] unable to verify link request"
When this occurs on a machine it wont't work, you can retry and retry...
if it worked, it works like a charm and in future I always get the linked account directly from the library without the login window.
What does this error mean and what can I do?
AppDelegate:
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Dropbox API Key & Secret
let _appKey = "------"
let _appSecret = "------"
// Accountmanager
if (DBAccountManager.sharedManager() == nil)
{
let accountManager = DBAccountManager(appKey: _appKey, secret: _appSecret)
DBAccountManager.setSharedManager(accountManager)
}
....
}
The linking in my class, when user clicked to activate dropbox:
internal func __start(parentWindow:NSWindow?, callback:((Bool) -> Void))
{
let am = DBAccountManager.sharedManager()
if am == nil
{
NSLog("Dropbox not available!")
callback!(false)
return
}
// link account
let linkedAccount = am!.linkedAccount
if (linkedAccount != nil)
{
// Already linked
DLog("Dropbox link found.")
let fileSystem = DBFilesystem(account: linkedAccount!)
DBFilesystem.setSharedFilesystem(fileSystem)
callback(true)
}
else
{
// link with window must be in mainthread
dispatch_async(dispatch_get_main_queue())
{
am!.linkFromWindow(parentWindow) {
account in
if (account != nil)
{
DLog("Dropbox linked")
let fileSystem = DBFilesystem(account: account!)
DBFilesystem.setSharedFilesystem(fileSystem)
callback(true)
}
else
{
DLog("NOT LINKED (Dropbox)")
callback(false)
} // if - else account
} // accountmanager block
} // dispatchblock main
} // if - else linkedaccount
}
Here the full log, the app is not doing anything else:
2015-02-23 10:25:39.443 TestApp[39226:30958267] Dropbox init
<<<< MediaValidator >>>> mv_ValidateRFC4281CodecId: Unrecognized codec 1.(null). Failed codec specific check.
<<<< MediaValidator >>>> mv_LookupCodecSupport: Unrecognized codec 1
[10:25:40.979] mv_LowLevelCheckIfVideoPlayableUsingDecoder signalled err=-12956 (kFigMediaValidatorError_VideoCodecNotSupported) (video codec 1) at line 1851
<<<< MediaValidator >>>> mv_TestCodecSupportUsingDecoders: Unrecognized codec 1
<<<< MediaValidator >>>> mv_ValidateRFC4281CodecId: Unrecognized codec 1.(null). Failed codec specific check.
<<<< MediaValidator >>>> mv_LookupCodecSupport: Unrecognized codec 1
[10:25:40.979] mv_LowLevelCheckIfVideoPlayableUsingDecoder signalled err=-12956 (kFigMediaValidatorError_VideoCodecNotSupported) (video codec 1) at line 1851
<<<< MediaValidator >>>> mv_TestCodecSupportUsingDecoders: Unrecognized codec 1
2015-02-23 10:25:43.873 TestApp[39226:30958267] [ERROR] unable to verify link request
2015-02-23 10:25:43.879 TestApp[39226:30958267] NOT LINKED (Dropbox)
I have same issue [ERROR] unable to verify link request after long research and studying the DropBoxSDK I come to the point that this error occurs when state ID is different from value saved at key KDBKLinkNonce. Every time at new Session it generates new state ID. See below code of [[DBSession sharedSession] handleOpenURL:url] method.
- (BOOL)handleOpenURL:(NSURL *)url {
NSString *expected = [NSString stringWithFormat:#"%#://%#/", [self appScheme], kDBDropboxAPIVersion];
if (![[url absoluteString] hasPrefix:expected]) {
return NO;
}
NSArray *components = [[url path] pathComponents];
NSString *methodName = [components count] > 1 ? [components objectAtIndex:1] : nil;
if ([methodName isEqual:#"connect"]) {
NSDictionary *params = [DBSession parseURLParams:[url query]];
NSString *token = [params objectForKey:#"oauth_token"];
NSString *secret = [params objectForKey:#"oauth_token_secret"];
NSString *userId = [params objectForKey:#"uid"];
NSString *state = [params objectForKey:#"state"];
NSString *nonce = [[NSUserDefaults standardUserDefaults] objectForKey:kDBLinkNonce];
[[NSUserDefaults standardUserDefaults] removeObjectForKey:kDBLinkNonce];
[[NSUserDefaults standardUserDefaults] synchronize];
if (![nonce isEqual:state]) {
DBLogError(#"unable to verify link request");
return NO;
}
[self updateAccessToken:token accessTokenSecret:secret forUserId:userId];
} else if ([methodName isEqual:#"cancel"]) {
DBLogInfo(#"DropboxSDK: user cancelled Dropbox link");
}
return YES; }
For further reference please check this link dropbox-sdk-ios
I found something and since I found a fix for that, even the dropbox error is gone.
The problem seems to be, that NSUserDefaults did not store any data (not in memory and not on disk!). Since Dropbox uses NSUserDefaults to check the state before and after, this killed the whole process.
With getting the NSUserDefaults back working it seems the whole dropbox problem was gone.
OSX NSUserDefaults not Working
Old method
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:count];
is now gives error Attempting to badge the application icon but haven't received permission from the user to badge the application.
Then I tried to use new API (that I'm think is related to badge value)
CKModifyBadgeOperation * operation = [[CKModifyBadgeOperation alloc] initWithBadgeValue:50];
[operation setModifyBadgeCompletionBlock:^(NSError *error) {
NSLog(#"%#", error);
}];
[operation start];
But I'm receiving error <CKError 0x165048a0: "Not Authenticated" (9/1002); "This request requires an authenticated account">
How to set badge or receive some new permissions?
In addition to Daij-Djan's answer: it's possible to stack the enums so you can request them all at once. Like follows:
UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:notificationSettings];
Debug output mentions I should ask for Application Badge permission
to modify the badge under ios8 you have to ask for permissions
let settings = UIUserNotificationSettings(forTypes: UIUserNotificationType.Badge, categories: nil)
UIApplication.sharedApplication().registerUserNotificationSettings(settings)
or in objC
UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
Additional info for previous posts (in complete to registerUserNotificationSettings):
Apple makes new API for registering notifications and working with badges.
See WWDC 2014 session video , text version
and documentation.
User can change permissions for every UIUserNotificationType (UIUserNotificationTypeBadge, UIUserNotificationTypeSound, UIUserNotificationTypeAlert) in Settings.
Before changing badge you must check permissions.
Code sample from my AppDelegate:
#ifdef __IPHONE_8_0
- (BOOL)checkNotificationType:(UIUserNotificationType)type
{
UIUserNotificationSettings *currentSettings = [[UIApplication sharedApplication] currentUserNotificationSettings];
return (currentSettings.types & type);
}
#endif
- (void)setApplicationBadgeNumber:(NSInteger)badgeNumber
{
UIApplication *application = [UIApplication sharedApplication];
#ifdef __IPHONE_8_0
// compile with Xcode 6 or higher (iOS SDK >= 8.0)
if(SYSTEM_VERSION_LESS_THAN(#"8.0"))
{
application.applicationIconBadgeNumber = badgeNumber;
}
else
{
if ([self checkNotificationType:UIUserNotificationTypeBadge])
{
NSLog(#"badge number changed to %d", badgeNumber);
application.applicationIconBadgeNumber = badgeNumber;
}
else
NSLog(#"access denied for UIUserNotificationTypeBadge");
}
#else
// compile with Xcode 5 (iOS SDK < 8.0)
application.applicationIconBadgeNumber = badgeNumber;
#endif
}
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
The CurrentUserNotificationSettings method is available in the UI application instance and will give you the most up-to-date user notification preferences.
Working with badge number:
[self setApplicationBadgeNumber:0];
instead of
application.applicationIconBadgeNumber = 0;
PS: Checking at compiling (#ifdef __IPHONE_8_0) due to the need to build in Xcode5 and Xcode6.
If you do not have this need, the code can be simplified.
I write a class to handle it when I use swift:
class ZYUtility
{
/// Set badge
class func setApplicationBadgeNumber(badge: Int) {
if ZYUtility.SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO("8.0") {
if UIApplication.sharedApplication().currentUserNotificationSettings().types & UIUserNotificationType.Badge != nil {
UIApplication.sharedApplication().applicationIconBadgeNumber = badge
} else {
println("No permission to set badge number")
}
} else {
UIApplication.sharedApplication().applicationIconBadgeNumber = badge
}
}
/// System check
class func SYSTEM_VERSION_EQUAL_TO(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedSame
}
class func SYSTEM_VERSION_GREATER_THAN(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedDescending
}
class func SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedAscending
}
class func SYSTEM_VERSION_LESS_THAN(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) == NSComparisonResult.OrderedAscending
}
class func SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(version: String) -> Bool {
return UIDevice.currentDevice().systemVersion.compare(version,
options: NSStringCompareOptions.NumericSearch) != NSComparisonResult.OrderedDescending
}
}
update to 8.3, ObjC: we should add Daij-Djan script to replace NSLog(#"access denied for UIUserNotificationTypeBadge"); in Spidy & KepPM solution above. Hope this help s.o.