Is it safe to change notification names between App updates? - ios

My current notification names for NSNotificationCenter are constants, defined in a globally accessible singleton:
let notificationLeafletImageLongPressed = "com.mycompany.notificationLeafletImageLongPressed"
let notificationLeafletPageChanged = "com.mycompany.notificationLeafletPageChanged"
What I want to do is change it to something like this:
enum NotificationKey: String {
case LeafletImageLongPressed
case LeafletPageChanged
}
// Access
print(NotificationKey.LeafletImageLongPressed.rawValue)
In this way I have the compiler check that all names are really distinct.
I have now three questions:
1) As far as I understand updating an App on the device over the App Store always leads to terminating (and therefore to a re-start) of the App. Right?
2) Therefore it should be save to change notification names for NSNotificationCenter between updates. Right?
3) Currently the names are defined in reverse dns style (com.mycompany.notificationName) but afterwards they will just be notificationName. If this generally ok to do? Or should it be always reverse dns style? (then I can't change it to enums)
Thanks in advance.

1) Yes, after an update, the app restarts.
2) Yes, it will save change to notification name because the change is in code and not in some persistent container (Keychain, UserDefaults etc).
3) 'notificationName' looks much better than 'com.mycompany.notificationName'. Although Apple recommends much more verbose names in their coding guidelines.
https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/CodingGuidelines/Articles/NamingIvarsAndTypes.html
Notifications are identified by global NSString objects whose names
are composed in this way:
[Name of associated class] + [Did | Will] + [UniquePartOfName] +
Notification For example:
NSApplicationDidBecomeActiveNotification
NSWindowDidMiniaturizeNotification
NSTextViewDidChangeSelectionNotification
NSColorPanelColorDidChangeNotification

Related

can we release same app with 1 or 2 different functionality for 2 different countries?

I want to release my app in only 2 country and i want to do 2 different functionality for both country.
For example.
ViewController1 functionality is different in Jamaica.
ViewController1 functionality is different in Kenya.
Different functionality means content is different, or input forms are different.
Is it possible? if yes then please refer some document.
Thanks in advance
You should have a screen that allows user to select their country, after that, store selected country in our app (by UserDefault or Keychain, etc...).
Based on the selected country then you can switch logic/layout to adapt the requirement above
some notes about App Store:
1) language should / must be selected by user on Prefs, NOT in Apps.
Chances Apple will refuse apps not following above logic.
2) You could test current language / Zone using code (see below for language)
BUT I think Apple can refuse as you use a different behaviour
3) if really you need it, You can load a different controller using Storyboards (I suggest using different storyboards AND lod them at runtime using segues and "*.soryboard" as in:
func ViewControllerFromStoryboardWith( name: String ) -> UIViewController {
// we use an identifier equal to filename for now.
let storyboard = UIStoryboard(name: name, bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: name) as UIViewController
return vc
}
// test lang:
func currHWLanguage()->String{
let defs : UserDefaults = UserDefaults.standard
let languages : NSArray = defs.object(forKey: "AppleLanguages") as! NSArray
let current = languages[0] as! String
// since 9.0 we get en-US etc.. so cut to 2:
let result = (current as NSString).substring(to: 2)
#if DEBUG
// force to IT as a bug in simulator
// return "IT"
#endif
return result.uppercased()
//NSLog("%#", current)
}
This is a problem many applications are trying to solve. Basically, you have the following options:
Let the user choose. This is the safest option if one application contains two different configuration.
Try to detect location of the user. Language/Locale is unsafe because many people will have English (or different) locale set up. Very unsafe. You shouldn't ask for GPS location for this. The safest option is to create a server request and check the location using the IP address. A bit complicated and won't work if a VPN is used (e.g. antivirus apps create VPNs).
Create two different apps. In the end, this is the best option. Add a second application target to your project and release two separate apps with separate configuration.

iOS Notification Content Extension - How to pass data to app?

I wrote a custom Notification Content Extension for my Push Notifications like this:
The thing is, whenever the user is on a certain item in the carousel, I want the GO TO APP button to send a String to the app when it's opening, and from there, handle that string to move the user to the correct ViewController.
I already have the handling part inside the app, I just need to know how to pass that String from the Notification Content Extension to the container app.
Thanks! :)
Enable app groups in capabilities and use suite userDefaults to write the key and read it in the app
NSUserDefaults*defaults= [[NSUserDefaults alloc] initWithSuiteName:#"group.com.company.appName"];
// Write in extension
[defaults setObject:#"anyThing" forKey:#"sharedContent"];
// Read in app
[defaults objectForKey:#"sharedContent"];
If your app is configured for Universal Links or you have defined a Custom URL Scheme for your app, you can also open your app's URL (e.g. with data in query parameters) by calling
extensionContext?.open(url)
in your NotificationViewController.
iOS 13, Swift 5.
Based on the answer by Sh_Khan, here is some Swift Syntax. Obviously I have added App Group as a capability to the target of the main app + the target of the extension, naming the group as "group.ch.Blah" for this example.
Setting your app group, saving a string in our case, needed to set the type as Any cause strings not a type that is available in groups.
let localK = getPrivateKey64() as Any
let defaults = UserDefaults.init(suiteName: "group.ch.Blah")
defaults?.set(localK, forKey: "privateK")
Setting your app group, and reading the string back, needed to recast it back to string.
let defaults = UserDefaults.init(suiteName: "group.ch.Blah")
let localK = defaults?.object(forKey: "privateK") as? String
Worked perfectly with a notification service extension.

How to use SpringboardServices to get notifications count of an app ios

How can I get notifications count of another app into my app by using SpringboardServices and SBSPushStore?
I'm trying to show notification count taken from whatsapp into my app so I was searching around and one thing is for sure that it is possible but I didn't find any approbate way on how to do it.Here is the question which answers it but I didn't get it. How to do it? Can someone please share the step by step procedure.
Based on the question I was able to find the code which can actually lock you iphone using SpringboardServices but I don't know how to use it for SBSPushStore?
void *SpringBoardServices = dlopen("/System/Library/PrivateFrameworks/SpringBoardServices.framework/SpringBoardServices", RTLD_LAZY);
NSParameterAssert(SpringBoardServices);
mach_port_t (*SBSSpringBoardServerPort)() = dlsym(SpringBoardServices, "SBSSpringBoardServerPort");
NSParameterAssert(SBSSpringBoardServerPort);
SpringBoardServicesReturn (*SBSLockDevice)(mach_port_t port) = dlsym(SpringBoardServices, "SBSLockDevice");
NSParameterAssert(SBSLockDevice);
mach_port_t sbsMachPort = SBSSpringBoardServerPort();
SBSLockDevice(sbsMachPort);
dlclose(SpringBoardServices);
The answer to that linked question you commented on implies that you don't need any framework, as long as your device is jailbroken.
You simply load the plist file located at /var/mobile/Library/SpringBoard/applicationState.plist. The format of that answer is a bit broken, but I assume the > are meant as indicators to explain the inner structure of the file (i.e. key values).
So from that I assume it's a dictionary, you can load it by
NSDictionary *plistFile = [NSDictionary dictionaryWithContentsOfFile:#"/var/mobile/Library/SpringBoard/applicationState.plist"];
NSDictionary *entryForYourApp = plistFile[#"com.app.identifier"]; // obviously you have to use the identifier of whatever app you wanna check
NSInteger badgeCount = entryForYourApp[#"SBApplicationBadgeKey"];
You probably want to inspect the file yourself first (so set a debug point) and make sure its structure is like I assumed, the types are correct and so forth (not to mention it exists, Apple sometimes changes stuff like that and the other question is already several years old).
In general be aware that you can only do that, as said, on a jailbroken device. Otherwise your application simply doesn't have reading access to the path /var/mobile/Library/SpringBoard/applicationState.plist. Or to anything outside its sandbox, for that matter.

For plug in running on iOS

What I want to implement is as follow:
A-app (calling app) : request the return value of a-string sent as parameter : request(a-string) -> b-string.
B-app (plug-in installed separately by me or others, it plays the role of dictionary or database ) : search a-string from database and return the result (b-string).
With successful experiences of plug-in on android and with Apple's confident rhetoric of plug-in, I thought plug-in, of course, run on iOS. After a lot of hard work, however, I finally found out:
* Note : The creation and use of loadable bundles is not supported in iOS.*
Nonetheless, not giving up, I finally made it with custom URl and pasteboard:
A-app : write a-string and false state to pasteboard & call B-app via custom URL.
B-app : viewDidLoad runs following func and thereafter exit program ; func { read pasteboard and search from database & write the result(b-string) and true state to pasteboard }
A-app : while-loop detects whether state is false or true. if true, catch b-string from pasteboard.
Anyway it works but it's too long thus almost useless. Do you have any idea for better solutions? Why doesn't Apple allow plug-in for iOS? Any responses are welcome. Thank you.
I can't answer why Apple doesn't allow plug-ins, but I can offer some advice on what you're trying to achieve.
The common pattern for sending data back to your application is to implement a callback url, so the A-app would also implement a custom URI and add that to the uri sent to B-app.
B-app would then process the uri as you have already implemented, but then instead of exiting, it simply sends the data you requested in the uri passed to it.
See http://x-callback-url.com for more details and example implementations.

Gracenote API - No track link data

Currently, in my AppDelegate, I have an instance variable declared for GNConfig that is set up with all properties I would like to receive.
This instance of GNconfig is used by any class that makes a gracenote request.
The requests I am using are recognition from an audio stream, recognition by local file and a text search which populates an array. The array is then used for track lookups by id for the corresponding array item.
I am able to get all the content I need, except for track and album link data (always returns null).
I have tried plenty of different suggestions and guides with no luck.
Could somebody please help me out? This data is essential to my app and my app is pretty much complete except for this big obstacle.
Thanks in advance.
** edit **
This is in my appDelegate:
_gnConfig = [GNConfig init:#"XXXXXXX-XXXXXXXXXXXXXXXXXXXXXXX"];
[_gnConfig setProperty:#"content.coverArt" value:#"1"];
[_gnConfig setProperty:#"content.coverArt.sizePreference" value:#"LARGE"];
[_gnConfig setProperty:#"content.allowFullResponse" value:#"1"];
I have this in one of my class methods:
NSURL *filePath = [item valueForProperty:MPMediaItemPropertyAssetURL];
[GNOperations recognizeMIDFileFromFile:self config:[[AppDelegate sharedDelegate] gnConfig] fileUrl:filePath];
In the delegate method I have:
gracenoteResponseItem = [result bestResponse];
NSLog("%#", [gracenoteResponseItem trackLinkData]);
Some tracks may not have link data available.
Also if you are doing a local lookup then you will have to set this config option:
[publicProperties setObject:#“1"forKey:#"content.allowfullresponse"];
Unless you have explicitly had your client ID entitled for Link IDs (aka 'external' or '3rd party' IDs), you won't get any in your responses.
By default, Gracenote Open Developer client IDs aren't entitled for any external IDs. You need to coordinate with Gracenote to entitle your client ID to start receiving the desired IDs.

Resources