iCloud KeyValueStore preference changes and handling them across various devices - ios

As per Apple's guidelines my app provides an option for user to enable/disable storage in iCloud.
Use case :
By default the storage in iCloud is disabled
User downloads the app on iOS Device 1 and creates some files etc
User then downloads the app on iOS Device 2 and create some files etc. These files are different from those created on iOS Device 1
User then enables iCloud on iOS Device 1. This setting is propagated to iOS Device 2 using KV store of iCloud. Also the files in iOS Device 1 sandbox are moved to iCloud
Scenario 1:
User starts the app on iOS Device 2. I know that now iCloud is enabled and I prompt the user that it was enabled on some other device and I am moving your local files to iCloud. I think there is no problem here.
Scenario 2:
When the notification arrived (that iCloud is enabled on device 1) user was using the app on iOS Device 2 and had few modal views on the screen. I am not sure how to inform the user about the change and perform the operation i.e move device 2's sandbox files to iCloud.
Should all the viewcontrollers of the app have the capability to be interrupted and handle this event ?
Looking for some suggestions and guidance here on the user experience and right thing to do.

Save the a device-specific setting in NSUserDefaults and don't upload files automatically — it seems a little wrong to automatically upload things because a setting changed on another device. If you force the user to navigate to an "Enable iCloud Storage" view controller, you have much more control over what other VCs are visible and are less likely to run into surprises.
It could also be worthwhile making it a per-file setting (e.g. perhaps files they don't want in iCloud for security/space reasons).
Alternatively, a UIAlertView should work from anywhere in your app, but you'll have to make sure that files can be shifted to iCloud seamlessly while they're being viewed (and edited?) in a view controller.

Related

iOS wont delete my App Data after uninstall of MAUI Application

I am using MAUI.Essentials to store data in secure storage.
SecureStorage.SetAsync(key, securedValue);
But uninstalling the Application in android is deleting app data but the same is not working in iOS.
According to this post we need to turn off the backup in iCloud.
I am currently testing in iPhone simulator and under settings I have not logged in to iCloud.
Also I tried below code to manually delete the app data
if (VersionTracking.IsFirstLaunchEver)
{
services.AppCache.Clear();
}
But I don't want to delete it manually.
Any help is appreciated!
Given that (by iOS design) there isn't any way to delete data from iOS secure storage when app is deleted, you'll want a way to detect that there is "obsolete" data there, if the app gets deleted then re-installed.
When you detect this, you can decide whether to ignore or delete that "obsolete" data, so that it isn't visible to the new installation. Thus, it is as if it was not kept (other than the slight waste of storage -- never put anything large into secure storage).
I do this by creating an empty file in app local (not secure) storage, at the same time as saving the data to secure storage.
When app starts up, I check if that empty file exists. If it is not there, then I know anything in secure storage is "obsolete", left over from a previous install of app, so I erase it (if I don't want it to be visible when re-install).
Note that this also handles the case where user goes to Settings, finds the app, and does "Delete Data". Even if they don't uninstall app, the next time it runs, it will act as if it is a new install.
In the Maui official document (Secure storage) wrote:
KeyChain is used to store values securely on iOS devices. The
SecRecord used to store the value has a Service value set to
[YOUR-APP-BUNDLE-ID].microsoft.maui.essentials.preferences.
In some cases, KeyChain data is synchronized with iCloud, and
uninstalling the application may not remove the secure values from
user devices.
You can try to turn off iCloud with a real device, iCloud cannot be used in the simulator. You also can let the app start to call the delete code in your question to determine whether it is the first installation to delete the data in the KeyChain.

How to read files of External Mass Storage Devices Without DocumentPicker? (iOS)

Just to give some context, there is an iOS app I'm building (in Xamarin) that requires the ability to fetch files (in an automatic way without having the user to navigate to the files and select them manually) that are stored on External Storage Devices (USB Sticks), and are connected (paired) to an iPhone/iPad.
Users connect a lighting cable to the iOS Devices, and plug their USB Sticks into this lighting cable. Here is an example of the cable that end users use to pair the USB Sticks with their iPhone/iPad, and the app then auto fetches these files from the USB Storage Devices.
The app then performs 2 functions:
It listens to notifications, for when a usb stick is paired with the iOS Device.
When it receives this notification, it then proceeds with querying the files on the USB Stick, and reads and processes the files. The app reads these files automatically and the user does not need to manually select these files
I've tried using External Accessory Framework, however that's only suitable for devices that you register with the MFi program.
https://developer.apple.com/documentation/externalaccessory
Notifications Center never seems to work (the Notifications that handle when a Device gets Connected and Disconnected, the delegates never get called), and I've tried using the Microsoft Helpers.
https://learn.microsoft.com/en-us/dotnet/api/externalaccessory.eaaccessorymanager.notifications.observedidconnect?view=xamarin-ios-sdk-12
I've also tried some 3rd party libraries, but haven't found anything useful.
It doesn't look Apple has any Api Available to auto query and read the files, without having to use a DocumentPickerController. I know this is because of the App Sandbox, and I cannot directly access the Removable Storage Devices.
Now for my questions:
Are there any 3rd party libraries anybody can recommend, that can help achieve most of the heavy lifting for this task? I'd prefer a library that's compatible with Xamarin, however if it's a native library (Swift or Objective-C Library, Cocoapods) I'm sure there is a binding I can use on nuget.
Does anybody have any snippets, or documentation, or can point me in the right direction here (Please feel free to post Swift, or Objective-c solutions here if you like)? Where should I look, which Apple Framework (iOS SDK) is most suitable to deal with this situation. And to summarise, is what I'm asking for at all possible on iOS, without having to jailbreak, or get around the App Sandbox?
Update
So I've tried the solution that #Saamer suggested:
Detect if USB is connected to iPhone device
Here is an example I wrote just to verify if the callback gets invoked, and the app can detect if a usb is plugged in.
CFNotificationCenter.Darwin.AddObserver("com.apple.mobile.lockdown.host_attached", null, (e, s) =>
{
MainThread.BeginInvokeOnMainThread(async () =>
{
var picker = await Xamarin.Essentials.FilePicker.PickAsync();
});
}, CFNotificationSuspensionBehavior.DeliverImmediately);
A file picker should immediately get invoked, and open up, once I plug the USB in, however this doesn't happen.
I'm happy for a solution right now which opens up a file picker, when the user plugs in a USB Device, and navigates to the root directory to start off with. So when the File Picker opens up the user should see this. Then they can select the files they want to transfer into the app.
I thought you needed to jailbreak but it seems unlikely, a solution is possible for <iOS 12
CFNotificationCenter's AddObserver seems to be usable for detecting when a device is connected using host attached and detached as shown here
Or if you don’t submit it to the App Store, you can use this
According to the Apple Docs
You can use the Files app and other supported apps to access files stored on external devices, such as USB drives and SD cards, connected to your iPhone.
Essentially you have to make your a "supported app". I have downloaded a free app called "Clockology" that I recommend downloading and playing with, which allows users to see data within the app as you can see below:
You generally use UIDocumentPickerViewController along with the right uttype to get the files from the Files apps or iCloud Drive, and you require activating the Key-value storage and iCloud Documents from iCloud entitlements capability. There's a lot of tutorials on UIDocumentPickerViewController usage, but you specifically want the capabilities that became available from iOS 13 onwards
This video from WWDC is the best example of getting to where you want. I also didn't find any 3rd party libraries that can help with this
——————-
Edit: If the app does not need to be distributed through TestFlight or the App Store, you can use IOKit and distribute through AppCenter, as long as you have the UDIDs of all the devices you need the app installed on (up to 100?)

Swift - how to access all pdf files on device

I am trying to build an app that will allow users to see all pdf files that are on the device (in some kind of a list with a preview) [Regardless of which app it belongs to on the device, all should be shown]. Is there anyway to achieve this?
Sorry but this is not possible on an iOS device because of a feature called sandboxing. Apple does not allow an app to access the sandbox of another app. Each app sits inside a sandbox of its own. This is iOS's security feature. There is no way to go around this feature.
Reference - About App Sandbox

Is there a way to not erase the documents directory when uninstalling the app?

I'm developing an AIR app for iPad, and I found that when I uninstall the app, the documents directory data gets erased, is there a way to keep this data even when I delete the app or this behavior is regulated by iOS and there is nothing I can do about it?.
Thanks.
No you cant
From The iOS Environment
For security reasons, iOS places each app (including its preferences and data) in a sandbox at install time. A sandbox is a set of fine-grained controls that limit the app’s access to files, preferences, network resources, hardware, and so on. As part of the sandboxing process, the system installs each app in its own sandbox directory, which acts as the home for the app and its data.
So you delete the application all the content regarding that particular app gets deleted.
as soon app get uninstalled the document directory folder also get deleted with that. Although you will not able to access that folder from other apps so there is no need to keep that.

Common iCloud container between Mac and iOS app?

I want to build an iCloud based app that runs on both the Apple platforms, iOS and Mac. The app will use UIDocument on iOS and NSDocument on Mac to have a document based synchronization model - documents created on iOS will be available on Mac and vice versa.
The particular problem I'm facing is that I want the same iCloud container on both the apps. XCode creates a default container for the app based on the App ID, which has to be different on both the apps because this seems to be an Apple requirement - no two apps can have the same app id even if they are on different platforms.
So I left the default created container alone and added another container on both the Mac app as well as the iOS app. The app seems to work fine, I can create a new file package in both the apps in the correct place, but I'm having 2 issues:
The container does not appear properly in the iCloud settings management screen. In the entitlements section in XCode, I named the container as com.mycompany.myapp.mycontainer in both the apps. In the settings screen in iOS (Settings -> General -> Usage -> Manage Storage -> Show All) my app is listed as "mycontainer" instead of the App's actual name as I expected. Is it possible to supply a name and icon in the App's Info.plist to make it list properly?
My NSMetadataQuery is not working properly. I had made the iOS app with the Empty Application template, so the Info.plist was not properly setup with the CFBundleDocumentTypes key but I figured that out and fixed it. For firing my NSMetadataQuery in the iOS app, I'm using:
[self.queryCloud setPredicate:[NSPredicate predicateWithFormat:#"%K like '*.myextension*'",NSMetadataItemFSNameKey]];
with the search scope set like this:
[self.queryCloud setSearchScopes:[NSArray arrayWithObjects:NSMetadataQueryUbiquitousDocumentsScope, NSMetadataQueryUbiquitousDataScope, nil]];
I run the query after establishing the container's URL, I get the started and finished gathering notifications, but never the update notification from the NSMetadataQuery. Unless I go ahead and create a new document. If I create the document then I get notifications for Update, but only in that session. Next time I start up the app, the same settings don't give me any update notifications from NSMetadataQuery.
What am I doing wrong? Any pointers to articles on creating an iCloud document app targeting both Mac and iOS would be much appreciated! Suggestions, thoughts are most welcome.
I don't know about your NSMetadataQuery issues, but adding a shared iCloud container is easy, as long as you get the gotcha:
Pick one app ID that will be your shared cloud container. Doesn't matter if iOS or Mac OS X, you need to publish this app and it must be approved from the Apple Review Team* before your iCloud container will be available to any other app. e.g.
com.company.myawesomeapp
Note that you must not use a container name after your app ID (com.company.myawesomeapp.cloudcontainer), just use your appID!
Pick a second app ID (doesn't really matter), and create your second app. Open up Xcode and enable iCloud in the Capabilites Pane. Then under "iCloud Container Identifiers", add the identifier of your first (published and approved!) app
com.company.myawesomeapp
That's it!
There's just this one catch and that's the bottom line:
In order to use a container, an app must be available and approved. Before approval no other app may access your container, because technically it only exists as soon as your app is approved. Actually, it doesn't have to be available in the AppStore, it just needs to be approved (can be on developer held release).
You can only use a (shared) iCloud container if your app is published and has been approved.

Resources