I have an app with an extension on iOS8.
In extension, I make calls to my own API server with parameters those include "application version".
I can keep extension version and app version equal on every application deployment to App Store.
I can set application version to shared NSUserDefaults that can be read by extension.
I don't prefer above solutions. Is there anyway to get the containing application's version dynamically?
Have you ever tried to access infoDictionary? You can reach many information about your app from that.
For current version;
[NSString stringWithFormat:#"current version = %#", [[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"]]
Related
I'm working in a view where I should customize it regarding if there is a Watch Version of the app.
I know that I can use:
[[WCSession defaultSession] isWatchAppInstalled]
(but that is not what I want because the user can uninstall the app in the Apple Watch but the iOS app will still have the Watch Version available to install)
also:
[[WCSession defaultSession] isPaired] is not my case.
Actually isWatchAppInstalled is the correct way to deal with this scenario.
As the documentation states:
The user can choose to install only a subset of available apps on Apple Watch. The value of this property is true when the Watch app associated with the current iOS app is installed on the user’s Apple Watch or false when it is not installed.
https://developer.apple.com/documentation/watchconnectivity/wcsession/1615623-iswatchappinstalled
The property does not look inside the bundle to see if a Watch app is available. It will only return true if the Watch app is installed on the currently paired Apple Watch. If the user deletes the Watch App from the watch it will return false.
After checking the current project that I'm working on and also testing creating two new projects to check the bundles (one project with watch and the another without watch included), I saw the difference between them:
The difference is that the project with the watch included has a Build Phase that has the Watch app embedded in the subdirectory called "Watch".
Also we can see the "Watch" folder when Showing the Package Contents of the build in Finder:
So the condition whenever that iOS app has Watch embedded in code is:
+ (BOOL)isWatchAppEmbedded
{
NSString *watchPath = [NSString stringWithFormat:#"%#/%#", [NSBundle mainBundle].resourcePath, #"Watch"];
BOOL isDirectory = YES;
if ([[NSFileManager defaultManager] fileExistsAtPath:watchPath isDirectory:&isDirectory]) {
return YES;
}
return NO;
}
I've built a today widget and I want to show what version is running in my host app's about screen. Is there a way to do that?
I've tried replacing [NSBundle mainBundle] with bundleWithIdentifier but that fails. So, is there a way to get the infoDictionary from he extension bundle, or am I wasting my time?
You can pull this off by specifying the direct path to the extension's bundle. It looks like app extensions live in the PlugIns/ folder in your app's main bundle. You can create an instance of NSBundle by using -initWithPath:. For example:
- (NSBundle *)appExtensionBundle {
NSString *plugInsPath = [NSBundle mainBundle].builtInPlugInsPath;
NSString *appExtensionPath = [plugInsPath stringByAppendingPathComponent:#"MyTodayExtension.appex"];
return [[NSBundle alloc] initWithPath:appExtensionPath];
}
NOTE: This code was tested only with a Today extension. You should test to make sure it works correctly if you have other types of extensions.
You can't. Application and Extension cant access each others code and address space. They can only share data using Sharing the container using AppGroup or by using Shared NSUserDefault.
Using both the approach will require to run your extension atleast once.
I am developing an app for iPad which is using webservices. In current version I have a constant string which is the address of the server. Each time I want to check something I just change the address (from production, freezed version of app to preproduction, version that is equal to repository). The problem is I would like to have two versions of an app on iPad, but I think as long as the bundle identifier is the same it isn't possible. What is the proper way of doing so without creating another project? Can I have "two targets" which can distribute both versions of app with the only difference being the webservice address?
This problem will escalate when application will be delivered to the client, because whenever I will deploy test version the "freezed" version will be deleted.
Should I change the bundle identifier each time I change webservice address before deploy? Or maybe there is some "automated" way of doing so?
Thanks in advance
I wouldn't rely on the bundle identifier for your service call as you will end up with many version of your API in the server that you need to maintain. What you can do is to create a new target on your project and add a Pre processor macro to your Build settings and then you reference on that macro in your code to decide which URL use.
Then on your code:
- (NSURL *)url {
NSString *urlString = #"your://standars.url";
#if APITEST
urlString = #"your://test.url";
#endif
return [NSURL URLWithString:urlString];
}
Is there any way to know that iOS app is launched after being updated?
I think i can save app current version every time i launch the application for example in NSUserDefaults and check this version every time i open the application.
And what about the case:
1) User installs app version 1.0 , but doesn't launch it.
2) User installs app version 2.0.
How to handle that case for example?
Thanks in advance.
If always done what you have suggested, saving the app version in the NSUserDefaults.
And about your other case, if the app does not start with version 1 then it does with version 2 you could just see it as a new install.
Since your app never started in the first place you can just treat it as a fresh install. If you doing this to track update in some kind of analytics tool you will have an issue. But you could use apple install/update reports to get the correct list of install/updates.
Just be sure that if you do any updates from any version you make you code in such a way that you can upgrade from any previous version. So installing verion 4 from 1 will preform any and all changes for version 2 and 3 as well.
I found the following note at this website from Apple.
When a user downloads an app update, iTunes installs the update in a new app directory. It then moves the user’s data files from the old installation over to the new app directory before deleting the old installation. Files in the following directories are guaranteed to be preserved during the update process:
/Documents
/Library
Although files in other user directories may also be moved over, you should not rely on them being present after an update.
In every version you release, you can put a txt file with a unique name (unique for every version) in one of these update-persistent directories and check for the previous version txt file(s) at initial launch of application. This should work even in the case where your application was not launched between the download and an initial update.
Every time your application is launched, the following function in your appDelegate class gets called after the launching process is complete:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
This is a point where you can check the version of the application, probably using somoething like:
[[[NSBundle mainBundle] infoDictionary] objectForKey:#"CFBundleShortVersionString"]
I'm a bit late to the party, but if this is still an issue, I use a saved Boolean to see if this is the app's first launch:
if (![[NSUserDefaults standardUserDefaults] boolForKey:#"HasLaunchedOnce"]) {
NSLog(#"First launch");
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setBool:YES forKey:#"HasLaunchedOnce"];
[defaults synchronize];
}
I can then deal with an install or update as you already mention in your question.
I think this could be useful: MTMigration manages blocks of code that need to run once on version updates in iOS apps. This could be anything from data normalization routines, "What's New In This Version" screens, or bug fixes.
It is available through CocoaPods: pod 'MTMigration'
Please take a look to MTMigration repository at GitHub (https://github.com/mysterioustrousers/MTMigration) for usage and examples.
[MTMigration applicationUpdateBlock:^{
/* This code run on every version change. */
}];
[MTMigration migrateToVersion:#"1.0" block:^{
/* This code only run once in version 1.0 */
}];
[MTMigration migrateToVersion:#"2.0" block:^{
/* This code only run once in version 2.0 */
}];
If a user was at version 1.0 , skipped 2.0 , and upgraded to 3.0 , then both the 1.0 and 2.0 blocks would run.
This question was already answered but in iOS 6 all these solutions doesn't work.
My current solutions sometimes doesn't work too:
https://itunes.apple.com/us/artist/developer_name/developer_id
https://itunes.apple.com/us/app/app_name/app_id
the problem is in iOS 6.0.1, but no error with iOS 6.1
This works on my end (Xcode 5 - iOS 7 - Device!):
For the app itself:
itms-apps://itunes.apple.com/app/idYOUR_APP_ID
Code snippet (you can just copy& paste it):
#define YOUR_APP_STORE_ID 545174222 // Change this to your app ID
static NSString *const iOS7AppStoreURLFormat = #"itms-apps://itunes.apple.com/app/id%#";
[NSURL URLWithString:[NSString stringWithFormat: iOS7AppStoreURLFormat, YOUR_APP_STORE_ID]]; // Would contain the right link
For the developer you can use this:
https://itunes.apple.com/artist/idYOUR_ARTIST_ID
You can get YOUR_ARTIST_ID from your iTunes Connect or from the link on one of your apps (there is a "View more by this developer" and copy the number after the "id" on the link itself).