iOS - App Files not deleted when app is deleted - ios

We ran into strange behavior.
Install the app from test flight
App creates a local sqlite database in the NSDocumentDirectory
User deletes the app
User reinstalls the app again from test flight (newer version)
App sees old database in the app
This has happened several times. And my understanding was that apps are supposed to delete everything with it once they are deleted. Yet intermittently this happens.
Anyone seen this issue before?

I assume this is caused by iCloud backup and restore functionality. If you don't set the exclude back-up key explicitly, the iOS will automatically back-up your files in the document directory. In your case, the previous database was backed-up in the iCloud and when you re-installed the app, the iCloud restored the database file. That's the reason why you are seeing the old data. If you don't need to back up your app's database file use the following code:
Swift 4:
do
{
var resourceValues = URLResourceValues()
resourceValues.isExcludedFromBackup = true
try databaseURL.setResourceValues(resourceValues)
}
catch
{
print(error.localizedDescription)
}
Old Version Code
do
{
// Database URL
try databaseURL.setResourceValue(true, forKey:NSURLIsExcludedFromBackupKey)
}
catch let error as NSError
{
print("Error excluding \(URL.lastPathComponent) from backup \(error)");
}
Reference: How do I prevent files from being backed up to iCloud and iTunes?

Related

Multiple firebase apps, crash reporting configuration issue

I have configured multiple firebase databases in my single iOS app.
here is the code in my AppDelegate, that selects which firebase db I have to choose at run-time
func initFirebase(){
// Check the Flag which Firebase to connect with
if (UserDefaultsManager().getFirebaseConfiguration()){
let resource = UserDefaultsManager.env_firebase?.value(forKey: "resource") as! String
print("resource \(resource)")
let filePath = Bundle.main.path(forResource: resource, ofType:"plist")
let options = FirebaseOptions(contentsOfFile:filePath!)
FirebaseApp.configure(options: options!)
}
}
This is all working fine.
Issue is with crash reporting, I have to make the firebase crash reporting dynamic too.
Right now I have configured my firebase crash reporting with jBackend-genetech-dev-crash-reporting.json , here is my crash reporting shell script.
# Replace this with the GOOGLE_APP_ID from your GoogleService-Info.plist (its my genetech-dev firebase service account actually) file
GOOGLE_APP_ID=1:740631780656:ios:ddccc74c2f726b3a
# Replace the /Path/To/ServiceAccount.json with the path to the key you just downloaded
"${PODS_ROOT}"/FirebaseCrash/upload-sym "${SRCROOT}/JamesApp/jBackend-genetech-dev-crash-reporting.json"
So When I connect my app to the firebase db with configuration defined in service account GoogleService-Info.plist its working flawlessly i.e I am getting the crash reports with the exact line number of the crash. here is the screenshot.
But whenever I connect with other firebase accounts example GoogleService-Info-mh6-prod.plist, I am getting the crash reports in this case too but with no Line number, see screenshot below.
More Info
Am I testing on real device? Yes
Is bitcode support disabled in my project? Yes
Question:
How to make my crash reporting script dynamic in my case.
I have seen this iOS Firebase Crash Reporting - Error running build script , i.e making the script dynamic depending upon the app configuration variable i.e release/debug. but my scenario is different, my app select the firebase database depending on the app's System settings bundle. seen screenshot below.

iOS Data protection on core data not working

I am trying to enable the data protection for my core data file. Here is what I did.
Project settings enabled the data protection in capabilities.
Modified persistent store coordinator getter
let coordinator = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel)
let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("SingleViewCoreData.sqlite")
var failureReason = "There was an error creating or loading the application's saved data."
do {
try coordinator.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: [NSSQLitePragmasOption : ["journal_mode" : "DELETE"], NSPersistentStoreFileProtectionKey : NSFileProtectionComplete])
}
Ran the code and installed the app on the device.
Downloaded the app container and opened package content, and could see the .sqlite file
Now locked the device
Kept it for 10 sec, and then downloaded the app container again for the same app.
7.Opened the package content, I can still see the package content and sqlite file :(
I am using free provisioning profile if that helps in anyway.
What mistake am I doing here?? Why is this .sqlite file is not encrypted?
Please help. Thanks in advance.
Because the computer your device is connected to is a Trusted Computer, it can read your app's container even if the device is locked. I know of two options to test if the sqlite file is encrypted:
1) Jailbreak your device. Then SSH into your device, and try to read the sqlite file (ie. 'cat sqlite_file') when the device is locked. If the file is encrypted, you won't be able to read it.
2) You can inspect the attributes on the sqlite file and make sure the NSFileProtectionKey attribute is appropriately set:
let attributes = try? FileManager.default.attributesOfItem(atPath: sqlite_path)
print(attributes)

Save record to production environment

I need to save records to the production environment instead of the development environment in CloudKit. What I have tried to do in order to manage that is what many have recommended me. Submit a build of the app, and download it using TestFlight. That way, the records will be saved to the production environment, they said.
This is my code for saving records
func uploadRecordsToProduction() {
let cloudContainer = CKContainer(identifier: "MyContainserString")
let publicDatabase = cloudContainer.publicCloudDatabase
publicDatabase.saveRecord(record, completionHandler: {_,_ in
})
}
If I run the app in Xcode simulator the record gets saved in the development environment. If I run the app using Testflight, no record is being saved it seems. What is happening?

How to update/download the application within app itself

I have developed application in Swift. Application is enterprise application so it will never go live on App Store.
I need to update the application within app if update is available for the application.
Right now I have done with backend and iOS side code. I have created .plist file which contains my uploaded .ipa file url and other things. ref
I have successfully implemented code of how can I download and update the app within app itself.
But the issue is when app start to download it stops at 60% and when I try to retry download it's shows error Unable to Downlaod App.
Is there any way I can implement the same idea ?
Swift code
func getTheData() {
let appversion = NSBundle.mainBundle().infoDictionary!["CFBundleShortVersionString"] as! String
var query = PFQuery(className:"AppVersion")
query.getObjectInBackgroundWithId("Parse unique key") {
(version: PFObject?, error: NSError?) -> Void in
if error == nil && version != nil {
let oldVersion = version?.valueForKey("version") as! String
println(version?.valueForKey("version"))
if appversion == oldVersion {
println("Same Version")
}
else {
println(version)
println("Different version")
let url = version?.valueForKey("ipaURL") as! String
UIApplication.sharedApplication().openURL(NSURL(string:url)!)
}
} else {
println(error)
}
}
}
ANSWER:
I have found the issue.The issue is with iOS 9.0 and above only. From XCode 7 and above, you have to generate(Not manually) manifest.plist file with organizer only. When you are creating ipa file using export option in organizer you will get two options 1)Bitcode 2)generate manifest for OTA update. You have to crete Manifest.plist file with XCode's organizer only.
Seeing as the app is open, I would recommend showing the user a message to update. The AlertView button action should take the user to the webpage to download the new version.
This is not ideal from what you are trying to achieve, but is a way I have done it in the past and works fine.
The issue is the provision profile when you create Archive that time you need to correct device which is listed into provision profile.
Before few days same issue I face and connected same device along with provision profile UDID container.
So I created R&D over that and solve the same problem.

How to open a UIDocument after UIDocumentStateSavingError exists?

In my iCloud-based app, I noticed that if a crash were to occur while a UIDocument is open (and has not yet been closed), the status of the document sometimes becomes UIDocumentStateSavingError and it never opens successfully again.
When I run [UIDocument openWithCompletionHandler:] after this, the document never opens, returning NO for success and 5 (UIDocumentStateClosed and UIDocumentStateSavingError) for documentState.
On iOS 5, I also observed that NSMetadataQueryDidUpdateNotification is constantly being called (every second) until the file is deleted and the app is restarted. This causes additional usability problems in the app.
One more thing, on developer.icloud.com I noticed that the file is showing a second, conflicted version existing. This conflict isn't found on any of my devices, though, not even if the app is restarted or reinstalled.
What do I do to get the UIDocument to open normally?
Here is what I tried so far:
Checking [NSFileVersion unresolvedConflictVersionsOfItemAtURL:] for conflicts and removing all older version using [NSFileVersion removeOtherVersionsOfItemAtURL:].
Calling [[NSFileManager defaultManager] evictUbiquitousItemAtURL:] before calling [UIDocument openWithCompletionHandler:] to re-download the file to the device.
Downloading the main and conflicted versions from developer.icloud.com to see if any of them are corrupt or partial files. Both open fine.
Banging my head against my desk. Preliminary results are unsuccessful.

Resources