We need to test our app in the context of an iOS upgrade (e.g., 5.1 -> 6.0). Unfortunately, Apple doesn't allow downgrading devices. We thought of doing it in the simulator, but different versions of the simulator are different environments in themselves. I think we can copy the bundle from one simulator to the other, but that won't migrate the keychain (will it?).
Thanks!
To test a transition from one state (before) to another (after), you need a way to put the app in the before state.
Your app surely won't be running while the OS is being updated, so you really only need to worry about the app starting up and discovering that the OS has been updated. There are a couple options:
Copy all your app's data files from a device running the "old" iOS version (5.1 according to your question) to a device running the new (6.0) version. The organizer in Xcode will let you easily copy your app's "container" from a device to your Mac or vice versa.
Make your app write it's data in the "old" format. It's not uncommon for an app to have methods for reading and writing data in different formats depending on the environment, so it's often easier to get your app to write data out in the old format than to actually copy from an old device.
Whichever path you choose, think about any other places (like user defaults) where you might made OS version-dependent changes and set those back to values that correspond to the previous OS. This applies especially to keychain items, which aren't stored in your app's sandbox.
Unit testing frameworks (like Apple's XCTest framework) generally have a setup mechanism that you could use to reset your app to the before state, including copying files, adding and removing keychain items, setting defaults items, etc. You can then add unit tests that run whatever code might be involved in an update and test the results. With a set of easily repeatable tests you'll be able to debug any problems more easily.
However you approach it, the goal is to put the app in the same state that it would be in if it were running for the first time after an OS update occurred. You don't have to worry about simulating the actual OS update, you only need to trick the app into thinking that the update has just happened.
For now, you can still install iOS 8.2. When a new version is released, Apple leaves both versions open for installation for a short time. While that "signing window" is open you can upgrade a device, test, and then restore it from an image of the older version. So you could do some intensive testing while the window is open, but obviously that's not a long-term solution (it typically lasts only a few days).
If you have the budget for it, you could install 8.2 on a device, put a big sticker on it saying "do not upgrade", and keep it on 8.2 for as long as it's relevant. Install your app on that device and take a backup (with backup encryption enabled so that keychain entries will be included), then restore that backup to another device that's on 8.3 - this is basically the same procedure you'll go through when doing an upgrade/restore through iTunes so it should be pretty close. It won't be exactly the same as an OTA update on-device of course, but for that, see option 1 above (and see it soon).
Related
Before Swift 2.2 the UUID value was the same every time I opened the app, now changes at every opening
I use this code:
UIDevice.currentDevice().identifierForVendor!.UUIDString
How can I do now to identify the user?
Every time you delete the app, the UUID may change.
If you just close and open the app, it's should be the same.
But if you delete the app (or install it again via xcode), it might change.
There are a couple of answers that explain why the UUID is resetting. There's one that offers a potential work around, but I'd consider it far from ideal. But I want to highlight something important about the way UUID's work that serves as a great workaround that has absolutely zero impact on the production OR debug version of your code base or compiled binary.
The value in this property remains the same while the app (or another app from the same vendor) is installed on the iOS device. The value changes when the user deletes all of that vendor’s apps from the device and subsequently reinstalls one or more of them.
All you have to do to prevent this value from changing while developing App-A is to simply install App-B from the same vendor (yourself) and keep it installed during the life time of App-A's development. This is literally as simple as starting a blank new iOS project and install the blank slate to your test device (using the same developer account & such), and then never uninstall it again during development.
App-B keeps a constant UUID for the vendor (yourself) so no matter how many times you delete and reinstall App-A, it will always keep the same UUID.
This actually seems to be a bug IMO. Everytime I run my app in the simulator it generates a new Vendor ID. You can probably get round it by storing the ID into NSUserDefaults on the first bootup then retrieving / comparing the value from NSUserDefaults instead of getting it from identifierForVendor. This will save a static vendor id in defaults but in theory the vendor id will still be changing every boot up.
Kind Regards,
Krivvenz.
Update: I can confirm I have installed multiple apps on the same simulator too but the vendor ID is still changing on every boot.
Update 2: - I have logged this as a bug with Apple - 26195931.
The value of this property is the same for apps that come from the
same vendor running on the same device. A different value is returned
for apps on the same device that come from different vendors, and for
apps on different devices regardless of vendor.
The value in this property remains the same while the app (or another
app from the same vendor) is installed on the iOS device. The value
changes when the user deletes all of that vendor’s apps from the
device and subsequently reinstalls one or more of them. The value can
also change when installing test builds using Xcode or when installing
an app on a device using ad-hoc distribution. Therefore, if your app
stores the value of this property anywhere, you should gracefully
handle situations where the identifier changes.
Refer this link for more info.
I have been working on an app in Xcode (not submitted to the App Store or anything like that) that has a lot of very important data whose loss is insurmountable. The app has recently started crashing on startup; therefore, I have tried to update the code to Swift2 so that it works.
After having Xcode automatically update this app to the new version of Swift, I have been having a major issue: When I re-download the app using a cable plugged into the iMac and the iDevice, the new version of the app does not replace the old one––it adds another app to the device. Why would this be happening, and, more importantly, is there any way to fix that?
The point of this is to retrieve the data which was saved in UserDefaults to the previous version of the app. Hence, I'll do pretty much anything to get that data back.
It is absolutely imperative that I retrieve the data stored in UserDefaults; the data is not stored anywhere else.
You are correct that the key is the bundle ID. We have a main bundle ID for production and a second target with a different ID for testing. Pretty convenient to have different versions of the app on the same device.
The second thing you can check is that the version number in the new project is greater than the version on the original project.
To see what apps and versions are installed on your phone, go to Devices (Shift-Command-2). Select your phone from the list on the left and the manually installed apps will be listed near the bottom. Sometimes this gets covered by the Console messages so you might need to scroll down.
Here's what the Device Manager looks like--I deleted my console logs...
Here is the Installed Apps view. It is behind the console logs so you need to scroll down in the top area...
I've been experiencing, of late, a weird problem with every App I create. When I deploy it to a device, I notice that it takes a long time to launch. Whether I'm debugging via Xcode or just launching it anywhere, anytime. When I tap the App icon, it takes about 4 seconds before the actual App launches. During that time, the device is pretty much frozen until the App launches.
However, I have an App that's been distributed through the App Store and it doesn't seem to have this problem. It launches immediately. But when I provision my phone via Xcode (the same App that's on the App Store), I experience this problem.
My question is, is there some sort of debug info that's built into the App binary that causes these long delays during launch that's not built into release versions? If so, is there a way to disable it on debug builds?
I believe it's bug on xcode 6 I've experienced the same issues. I've figured out a way to launch my apps quicker.
Set Xcode to build into a fixed DerivedData location—otherwise every time you blow away DerivedData, you’ll have to repeat all these step. Go to XCODE
Settings > Derived Data > Advance > Select "Unique"
Make a new script. Say: quick_compile.sh. Give it the standard “#!/bin/bash” or whatever at the top and chmod +x it. 3. Do a clean build of your project. 4. Go to the Xcode Report navigator (Cmd-8), and choose the report for your recent build. 5. Type “merge” into the upper-right hand filter, expand the log for the “Merge Khan_Academy.swiftmodule” phase, and copy the contents minus the first line into your script.
Do the same for “i386.swiftmodule”. 3. Do the same for “link”. 4. Do the same for the file you’re iterating on (e.g. ContentItemView.swift); put this at the top of your script
Once you’ve got this set up for a file, just run your script to update the build for that new file. 2. Launch the app with Cmd+Ctrl+R in Xcode.
You’ll have to repeat these steps whenever new files are added to the project or to change the file you’re iterating on, unfortunately, but it’s good when you’re working on something focused
I Learned this efficient method from #andy_matuschak twitter he made
a post a while ago on how to do this so i don't take any credit for
it. I believe he released a PDF explaining it better. If you can't follow these instructions look for the pdf file
I was seeing the same problem #purrrminator was. I have an iOS 8.3 device used for testing here at a large company with a good number of provisions that ultimately found their way on to this thing. I app I'm testing now was taking many seconds to launch.
Based on:
https://apple.stackexchange.com/questions/148792/installed-provision-profiles-not-seen-on-ios8
What I did was set the time manually to a date well into the future allowing the existing provisions to expire and get auto-pruned. A quick reboot (for good measure) and a fresh install of the app and I was good to go (a reset was not an option for me).
Try to reset phone settings (not content!). It may solve some performance problems occasionally.
The only reason that I've experienced the same problem was in fact that I got tons of provision profiles installed on the device. Our development team has over 100 apps, so iOS has to deal with all the provision profiles mess while launching the app.
I'm looking for a solution how to remove all installed iOS-Apps from a device. I'm working on a project for iOS-Security. For different analytical stuff on a jail-broken device it's necessary to automatically install a fat bunch of apps, perform all the tests and remove them afterwards to get free space for further applications. The auto installation and test-logic is already done. I only stuck with the apps-removing part.
User installed iOS-Apps are located in /var/mobile/Applications/.
Each application has its own randomly named directory e.g. 7654BE30-F438-42CE-98E0-B95264458C49/.
To proof whether an application is already installed or not my software checks out the com.apple.mobile.installation.plist in /private/var/mobile/Library/Caches/
I've tried to remove the binaries of all applications in /var/mobile/Applications/ and there references in the com.apple.mobile.installation.plist. It seems like the iOS generates a new com.apple.mobile.installation.plist after each installation-process, so it makes no difference whether I remove all the entries out of com.apple.mobile.installation.plist or not. So if I would like to install an application which was already tested someday my software wouln't recognize that it's not installed yet, because it's still listed in com.apple.mobile.installation.plist.
I try to find out where the iOS stores all the information about a user installed application. Would appreciate any help or hint to find out the information. Thanks in advance!
Consider I'm working with an jailbroken iDevice, so everything is possible ;-)
Wipe whole device programmatically
Is there a way to programatically restore my iphone to factory settings?
Uninstall some app programmatically
if you want to uninstall apps, you can use private API "MobileInstallationUninstall". However, it requires entitlement "com.apple.private.mobileinstall.allowedSPI", which you can get, because your device is jailbroken.
When submitting an update to an app to the app store (via iTunes Connect?), is the update necessarily a whole binary? Can an update come in the form of a patch? If a second version of an app shares a lot of assets and logic from the previous version, does all that logic/resources get reinstalled wholly regardless?
There are no patches. It's installed as an entire read-only bundle. The old bundle is replaced with the new bundle.
Application data is retained (ie. documents folder, NSUserDefaults).
As everyone said before me Apple does not supply a way to hot-patch native apps, moreover it has a clear restriction - "No remote code injection".
The only thing I can add is that hybrid apps which use a javascript platform allow you to remotely replace the JS file, so you can actually change functionality remotely.(without having to release a new version) other solutions I have seen are in the gray area and allow you to run Lua Script remotely to change app functionality.
We # Rollout.io have a different approach, we allow you to hot-patch production apps without code injection on native applications, you can read more on how the tech works here
Rollout is meant to help mobile developers solve production quality issues, hot-patching production apps, debugging production env, adding/removing analytics, etc.
Disclosure: I'm from the Rollout.io team.
iOS 6 now supports delta app updates. This is awesome, and makes Real Racing 3 (a 1.1GB app) update in about 30 seconds instead of 20 minutes!
https://developer.apple.com/library/ios/#qa/qa1779/_index.html
Q: How can I reduce the downloaded size of my app update for users
that already have the previous version installed?
A: Starting with iOS 6, the app store will automatically produce an
update package for all new versions of apps submitted to the store.
This package is optimized for updating an app from one version to
another, and contains files that have changed between the prior
version of an app and the new version of the app, excluding files that
have not changed.
When used optimally, an update package is significantly smaller to
download than the full package of the app and the update will install
more quickly. Also, in many cases, this mechanism allows updates to
large apps to be downloadable over cellular networks where app
downloads are subject to a size limit.
In addition to new content, the update package contains instructions
on how to transform the prior version of the app into the new version
of the app. New files will be added, modified files will be replaced
with their updated counterpart, and deleted files will be removed as
part of this transformation. As far as the developer and user are
concerned, this process is entirely transparent and the resulting
updated app will be indistinguishable from a full download of the
corresponding updated version of their app.
Further instructions for developers available at the link above.