Set Permission to delete file in OS X swift 3.0 - swift

I coded for osx application to remove file from directory path but I had received error as "couldn’t be removed because you don’t have permission to access it". So I want to set access permission code to remove that list of files. If any one have idea or solution please help me. The code as pasted below for reference :
if fileManager.fileExists(atPath: fullpath) == true {
print("File Available \(fullpath)")
do {
_ = try fileManager.removeItem(atPath: fullpath)
} catch let error as NSError{
print(error.localizedDescription)
}
}
In above code, I had found the exist file in directory but I got error that "couldn’t be removed because you don’t have permission to access it".
I want to get solution of access permission and remove file from directory. Thanks in advance.

If you want your app to be able to access files outside your own app, you need to turn App Sandbox off in your app target's capabilities.

Related

How to solve Swift FileManager couldn’t open file because of permission and implement file access

I made a music app for macOS that need the access of the file on disk. I can get the proper url, but I can't access the file. To figure out that problem, here I create a concise code snippet to concentrate on the question itself.
.onAppear {
var url = FileManager.default.homeDirectoryForCurrentUser
url.appendPathComponent("Downloads/Test.txt")
var text: String = ""
do {
text = try String(contentsOf: url)
} catch {
print("ERROR: \(error.localizedDescription)")
}
}
The output would be like this
ERROR: The file “Test.txt” couldn’t be opened because you don’t have permission to view it.. So I noticed App Sandbox in Targets > Signing & Capabilities. But at the list of file access (as you can see in the following picture), there's only User Selected File, Downloads Folder, Pictures Folder, Music Folder and Movie Folder. So I come up with 3 questions:
What that User Selected File means? Is that means that the user can select some specific file for my app to access? If it is, how can user selects them?
How can I get access to other folders like Desktop Folder if I remain the App Sandbox capability here?
I also noticed the trash icon on right-upper corner. If I delete App Sandbox, I can access every folder I want with the user's agreement by a default system pop-up. But what the deletion of App Sandbox means? Does it make my app "untrusted" somehow when user install it or others? Does it cause any security problems?
And It couldn't be better if you can tell me the conventions major developers follow when meet this problem. I would highly appreciate your help.

i want to ask for external storage access from the user to delete the files(songs)

File file = File(widget.singleTrack!.data);
try {
file.delete();
if (await file.exists()) {
print('Song not deleted');
} else {
widget.allSongs!.remove(widget.singleTrack);
}
} catch (e) {
print('$e');
}
This code does not work for external storage .
I think you need to append the root path of external storage which varies from OS to OS and device to device but with the help of ext_storage you can achieve it. Also take a look at this question
Regular File.delete() method would work for android 10 and below if you have writing permission but for android 11 and above you'd have to get the all files access permission.
To do so add this line in you android/app/src/main/AndroidManifest.xml,
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
And get the user to grant the permission like this,
if (await Permission.manageExternalStorage.request().isGranted) {...}
NOTE: Google doesn't appreciate this method. To properly delete you'd have to use MediaStore API for which you'd have to use native.

Catch Error Reading File From Disk - You Don't Have Permissions

I am using the following code in the AppDel. This is triggered when a user taps on a gpx file or uses the share option to share the file with my app. At this point it is the user that specified that they are allowing my app to access the file so I'm a little confused a to why this is still being denied. Any advice much appreciated.
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
if let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let fileURL = dir.appendingPathComponent(url.lastPathComponent)
if FileManager.default.fileExists(atPath: fileURL.path) {
print("File already exists")
}
else {
do {
try FileManager.default.copyItem(at: url, to: fileURL)
print("Did write file to disk")
}
catch {
DispatchQueue.main.async(){
print("Catch error writing file to disk: \(error)")
}
}
}
}
return true
}
The error prints to the console as follows:
Error Domain=NSCocoaErrorDomain Code=257 "The file
“Beech_Hill_Long_Route.gpx” couldn’t be opened because you don’t have
permission to view it."
UserInfo={NSFilePath=/private/var/mobile/Library/Mobile
Documents/com~apple~CloudDocs/Desktop/Beech_Hill_Long_Route.gpx,
NSUnderlyingError=0x282c19a70 {Error Domain=NSPOSIXErrorDomain Code=1
"Operation not permitted"}}
I'm less knowledgeable about exactly how this works on iOS, but I do have some knowledge about how it works for macOS, and the two should be similar. For macOS sandboxed apps the user has to select the file outside of the sandbox specifically via NSOpenPanel or NSSavePanel. The equivalent on iOS would be UIDocumentPickerViewController, but I assume an explicit share would work too. Based on that, here's how I would think about it and what I would try, if I were faced with your problem:
You've got two URLs involved in your call to FileManager.default.copy(). It's not clear which one is producing the error, so I'll consider both.
First let's look at fileURL. You're constructing it to put a file in the user's Documents directory. On macOS at least, that directory is not in the app's sandbox, which means asking the user via NSSavePanel (which also means they might decide to put it somewhere else). You might have to do the UIKit equivalent, or just make sure you're picking a location that is in your sandbox.
To test that, instead of doing the copy, try writing to fileURL to isolate just that one. For example:
do { try "TestString".data(using: .utf8)?.write(url: fileURL) }
catch { print("Write failed: \(error.localizedDescription)") }
If that fails, then your problem is with fileURL, in which case you may need to use UIDocumentPickerViewController to save it, or pick a location that's definitely in the app's sandbox.
If the test succeeds, the problem must be with the incoming URL.
I'm going to assume that url is already security scoped, because I'm not sure how sharing would even work otherwise. What I think is most likely happening behind the scenes is that when the user shares a URL with your app, iOS creates a security-scoped bookmark from the URL and sends the bookmark rather than the URL to your app. Then on your app's end, that bookmark is used to reconstitute the URL before passing it on to your app's delegate. If I'm right about that you'll need to open and close a security scope to use it:
url.startAccessingSecurityScopedResource()
// access your file here
url.stopAccessingSecurityScopedResource()
Note that stopAccessingSecurityScopeResource() has to be called on the main thread, so if you're code is happening asynchronously you'll need to schedule it to run there:
url.startAccessingSecurityScopedResource()
// access your file here
DispatchQueue.main.async { url.stopAccessingSecurityScopedResource() }
If you need to save the URL itself to use in a future run of your program... you can't. Well, you can, but it won't be valid, so you'll be right back to permissions errors. Instead you have to save a bookmark, and then in that future run, reconstruct the URL from the bookmark.
let bookmark = try url.bookmarkData(
options: .withSecurityScope,
includingResourceValuesForKeys: nil,
relativeTo: nil
)
bookmark is an instance of Data, so you can write that to UserDefaults or wherever you might want to save it. To get a URL back from it later:
var isStale = false
let url = try URL(
resolvingBookmarkData: bookmark,
options: .withSecurityScope,
relativeTo: nil,
bookmarkDataIsStale: &isStale
)
if isStale
{
let newBookmark = try url.bookmarkData(
options: .withSecurityScope,
includingResourceValuesForKeys: nil,
relativeTo: nil
)
// Save the new bookmark
}
Note that if isStale is true after the initializer returns, then you need to remake and resave the bookmark.
It's a shame that we have to go through this much trouble, but we live in a world where some people insist on doing bad things to other people's devices and data, so it's what we have to deal with the protect users from malicious data breaches.

Cannot open PDF using xcode for my iphone app

I have an iPhone app and I implemented a UIDocumentPickerViewController. Once the user chooses a PDF I receive the URL of the PDF.
I'm trying to get the Data for that PDF so I could send it to my server, but I get the following response:
Error Domain=NSCocoaErrorDomain Code=257 "The file “aaa.pdf” couldn’t be opened because you don’t have permission to view it." UserInfo={NSFilePath=/private/var/mobile/Containers/Shared/AppGroup/9C57E7F1-0997-4F57-A3EF-A7EFC3EF6158/File Provider Storage/aaa.pdf, NSUnderlyingError=0x282b43600 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}
This is how I try to convert it to Data:
var documentData = Data()
do {
documentData.append(try Data(contentsOf: documentURL))
} catch {
throw Error.Creation
}
I've read somewhere that sandboxed apps cannot read files, but when I'm looking into the target capabilities, I don't even see the Sandbox capability.
Any ideas why that happens?
Thanks
Updated to Swift 5 - Xcode 12:
In order to have read permission to the file you imported, add asCopy: true to the document picker:
let doc = UIDocumentPickerViewController(forOpeningContentTypes: types, asCopy: true)
Ok, the issue was I was using ".open" when creating the document picker instead of ".import". That did the trick.

Add the Association Domains feature to your App Id?

I'm trying to implement Firebase Dynamic Linking.
i have created project on firebase console and provided the required
value(prefx and appid).
i also have allowed the association domains from developer console
and it is sucessfully showing true flag.
in xcode i have on the feature of association domain and added the url identifiers etc.
Problem: still the problem i'm facing is that Association Domain Section says
Add the Association Domains feature to your App ID.
don't know whats the reason why i'm getting this error.
The screen shot is also attached for prove.
i have figured this out by searching for long time.
This is basically not a big issues the error
“Add the associated Domains feature to your App ID”
Will go away once you enable the Associated Domains in your APP ID in developer.apple.com. If it doesn’t go away, quit and relaunch the xcode few times and it will work.
reference: https://medium.com/#abhimuralidharan/universal-links-in-ios-79c4ee038272
I had a similar problem. The problem was solved when I turned off and turned on the feature in Capabilities. But then I had several entitlements files in different folders. Steps to combine these files into one:
Open in text editor MY_PROJECT_NAME.xcodeproj\project.pbxproj
Find CODE_SIGN_ENTITLEMENTS and set correct path. Example:
"MY_PROJECT_NAME/Entitlements/MY_TARGET_NAME.entitlements"
I do not recommend using a standard text editor, since it can automatically replace some characters in the file while saving.
You need to add Associated domains to your App Capabilities. Please see screenshot. Add applinks:yourdomain.com
Then Use below code to get Short URL
guard let link = URL(string: "https://www.yourdomain.com/share_location.html?Id=\(RandomID)&uid=\(uid)") else { return }
let dynamicLinksDomain = "yourdomain.page.link"
let components = DynamicLinkComponents(link: link, domain: dynamicLinksDomain)
// [START shortLinkOptions]
let options = DynamicLinkComponentsOptions()
options.pathLength = .unguessable
components.options = options
// [END shortLinkOptions]
// [START shortenLink]
components.shorten { (shortURL, warnings, error) in
// Handle shortURL.
if let error = error {
print(error.localizedDescription)
return
}
print(shortURL?.absoluteString ?? "")
}