Cocoa: how to Write file inside package contents of app - macos

When we try to delete/uninstall Cocoa .app file ,we directly move the .app file to trash.
This does not ensure the deletion of app user data folder in application support.
The user data lies there hanging. So i wanted to save the user data/ files inside application itself (app->showPacakge contents->somewhere).
If it is not possible! Any ways of clearing app user data folder in application support when user moves app to trash ?

Not a great idea.
The package content is signed. Any modification will be detected by the OS and will prevent launching of the app.
Not to mention the fact that you might not have access to the Applications folder, where most users will keep their app.

if you are using packages for installing your application, then you can have pre-install script, which deletes user data in the application support folder.

Related

Sharing Application Scripts directory between Mac Application and Extension + App Group

I will be running user-provided scripts via a Mac application and and an extension of the app. The app and extension both belong to the same App Group and individually have the correct entitlements to run scripts.
The Mac app is Sandboxed. According to Apple, any scripts must reside within the Applications Scripts directory: . applicationScriptsDirectory / NSApplicationScriptsDirectory.
The NSUserAppleScriptTask class is intended to run AppleScript scripts from your application. It is intended to execute user-supplied scripts and will execute them outside of the application's sandbox, if any.
If the application is sandboxed, then the script must be in the NSApplicationScriptsDirectory folder. A sandboxed application may read from, but not write to, this folder.
https://developer.apple.com/documentation/foundation/nsuserapplescripttask
The issue I'm facing is that the Main App and the App Extension resolve to different NSApplicationScriptsDirectories:
let applicationScripts = try! FileManager.default.url(for: .applicationScriptsDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
Different directories:
- ~/Library/Application Scripts/com.company.MainApp
- ~/Library/Application Scripts/com.company.MainAppFinderSync
I want to run the same scripts from both the App and the Extension. It works to launch scripts from each component's own Application Scripts directory, but the scripts are not launched if they reside within the other component's directory.
It is not ideal to maintain a synchronized directory structure, with matching scripts in both locations. It's also difficult to guide the user to put scripts in the correct location, as the main app's Preferences guide cannot open the extension's scripts directory.
App Groups solve this issue for other common app/extension scenarios, such as sharing data through NSUserDefaults:
After you enable app groups, an app extension and its containing app can both use the NSUserDefaults API to share access to user preferences.
https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html
Is there any ability to share an Applications Script folder between app and extension that belong to the same App Group?

Save Data Within Signed App

I am distributing my OS X application on individual USBs and, for this reason, everything must be self contained.
The app itself lets users input information and then saves this information to an existing text file (specifically an ObjectDB database). Herein is my problem.
I'd like to keep this text file inside the app itself (i.e. inside the Content folder) so it's out of the way and can't be deleted by the average user. But once the app is signed, it seems the text file can't be altered with any new information without getting flagged by Gatekeeper. Is this really the case? There's no way to store data files within apps now?
I'd appreciate any suggestions. Thanks.
Yes, you are correct. If you modify the application package, the signed package is no longer valid. That's kind of the purpose of signing a package.
Your options are to store the text file in a temporary folder on the user's computer, or to instruct your users to disable gatekeeper (don't do this).

Display PDF file in LocalState folder in Windows 8 app in Cordova

My application downloads a PDF and stores it in the LocalState folder for my Windows 8 app.
I have a link within the app that I would like to show the PDF when the user clicks it.
I've tried displaying it using ms-appdata:///local/pdfs/filename.pdf in a window.open call and I also tried using the InAppBrowser plugin within cordova with no luck. Additionally, I've tried the following:
var uri = new Windows.Foundation.Uri('ms-appdata:///local/pdfs/filename.pdf');
var file = Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri);
Windows.System.Launcher.launchFileAsync(file).done();
I know the file exists as I'm getting a file result back. Just not sure how to allow the user to view it.
By design, the local appdata folder on Windows is accessible only to that app, or to full-trust desktop applications (and this is probably true of similar sandboxed locations on other platforms). As a result, a Windows Store app that gets launched with Launcher.launchFileAsync won't be able access that location (nor can a webview process, which is also sandboxed). If a desktop application gets launched, on the other hand, it probably can access the file, but you can't tell ahead of time if that's the case. Bottom line is that local appdata isn't a good location for letting other apps get at the file.
You'll need to save the file in another location that is accessible to other apps. There are two approaches here, both of which will require a little user interaction to select a location, so they can place the PDFs anywhere they want:
Have the user select a save folder for your app, which they can do once. You would invoke the FolderPicker for this purpose, and save the selected folder in the FutureAccessList. This way you can have the user select the save folder, which grants you consent to save there, and by saving it in the FutureAccessList you can retrieve it in subsequent sessions without having to ask the user again. Refer to the File Picker Sample and the File Access Sample for more.
Have the user select a save location for each individual file, using the FilePicker (see the same sample), and you can also use the access cache to save permissions to those individual locations if you need them later.
There might be Cordova plugins that work with these APIs too, but I haven't checked. Either way, once the file is in an accessible location, launching the file should work just fine.
As an alternate solution, you could consider rendering the PDFs directly in your app. Windows has an API for this in Windows.Data.Pdf, with an associated sample. There might be a plugin or other JS libraries that could also work for this.

How programmatically delete files inside application folder in a sandbox enabled app

I'm trying to delete files inside application folder from my Cocoa application. By enabling Sandbox mode, I'm not able to delete files inside application folder.
This Sandbox mode has some option for enabling Read/Write access to downloads, pictures, movies, music and user selected file.
Before that I enabled Read and Write Access for user selected file and done my deletion using NSOpenPanel. It works fine and deletes files inside application folder but it opens panel every time when I run my app. Here I dont want any user interaction/permission to delete files inside application folder. Is there any solution to delete files with above defined constraints.
You need to use Security-Scoped Bookmarks:
Your app’s access to file-system locations outside of its container—as granted to your app by way of user intent, such as through Powerbox—does not automatically persist across app launches or system restarts. When your app reopens, you have to start over. (The one exception to this is for files open at the time that your app terminates, which remain in your sandbox thanks to the OS X Resume feature).

Writing to derived data in an archived app

I produced a .aiff file in my app and it's in my derived data folder, somewhere deep in the /Library. When I run the app in Xcode everything works fine. However when I archive it, the program crashes when it tries to write. How do I solve this? Do I need to learn to use Core Data or is there a easy fix?
Are you trying to write to the current working directory?
(If you're trying to do something like [foo writeToFile:#"output.aiff" …], you are.)
When you run within Xcode, the CWD is the build products directory within DerivedData where your application's bundle gets created.
When you run outside of Xcode, the CWD is the root of the startup disk, which you do not ordinarily have write access to and should never touch without explicit orders and permission to do from the user (via an Open panel or similar).
Either way, the CWD is the wrong place to put things.
You probably should run a Save panel, then write the file in your completion handler to the URL the Save panel has for you.
If you want to stash the file in some constant directory, ask an NSFileManager for the Caches folder in the user domain (~/Library/Caches), then tell it to create a folder inside that folder whose name is your main bundle's bundleIdentifier, then write the file in that directory.

Resources