mergeconflict296 === [00:00:00] Frank: Frank, [00:00:09] James: I hate secure. [00:00:11] Frank: I know, I know I, I already know what we're going to talk about today, so I'm just going to say it, everyone. We are dealing with the sandbox we've been dealing with it for 10 years, 12 years, 30 years. I don't know. It's been a whole lifetime and James it's wonderful because you and I have been chit chatting about the sandbox again, because what you're you're, you're changing your file IO and your app. It was the [00:00:38] James: best of times. It was the worst of times people ask for features and it's way more work than it was probably even worth to implement at the end. Now here's what a feature or a bug, a know a feature is it, this is a a hundred percent and feature requests of my application. Okay. So what we're talking about here is file access inside of a sandbox application and. I love the sandbox. Frank, I think the sandbox, I love the app store, the diploma, you get so many benefits we've talked about on this, on this, on this podcast. Before you do get security for your app, you get auto updating for your app. You get in-app purchases for your app. You get a seamless testing experience with test flight, um, and through the windows app store, I mean, there's so much to like about sandboxing. [00:01:32] Frank: Yeah, it's been pretty effective. I'd say it's worked out to the point where pretty much everyone's adopted it and no matter what platform you're on, you seem to be, get sandbox somehow or another. So, I mean, even like it or not, we're stuck with it and it does. Do you like it for the fact that you can't really mess up your system when you're doing development and things like that. That's kind of nice that isolation helps during development too. I will say the sandbox, not perfect though. You can still crash computers. You can crash, uh, iOS. It's pretty easy, but, um, otherwise I think they've succeeded in their role, but then there's the security part too. Yeah. [00:02:14] James: And you Frank have been talking about this for a year now, and we've been wanting to record a podcast on it for five years now, since we started the podcast now and I, and in my tweets, I, I, I tweeted to you as we may have covered some of this before me. I couldn't find an episode on it. Hmm. Or maybe it was a lightening topic or something like that. I'm not really positive, but if this isn't, you know, we've done so many podcast, Frank, that I don't even know what we've talked about in the past anymore. I've given up trying to understand enough what we do. Um, the here's the problem folks is when you want to write files or read files, it is. Extremely easy and run and did an Android too, by the way. And windows, all of them, they all have this problem all. Okay, got it. Uh, we're we'll specifically be talking about iOS and Mac iOS today. Cause that's where I'm implementing this thing and I'm inquiring windows for [00:03:15] Frank: now where you're dying fully dying. [00:03:18] James: So, uh, when you want to read and write things in a sandbox, you. Um, are recommended to keep those files in the sandbox. [00:03:30] Frank: Yes. Uh, so the operating system, it's documented somewhere. There's a bunch of, uh, defined paths where you are allowed to write files. And most of the time on iOS, we used to just dump everything in user's documents folder, but that's not quite right. There's applications, support directories. There's. Cash directories, which are kind of nice because they'll get emptied by the operating system. Uh, there are directories that get backed up along with your apps back up. So that's really nice. You want to make sure you're writing to those kinds of directories? Uh it's. That was it for iOS up to about version three or four ish. That was the extent of what you are allowed to touch. I actually kind of liked it back in the day. Remember we used to use like isolated storage and dotnet to, um, I love that because, uh, yeah, it seemed like a good security model and honestly, I kept your app, so. Uh, the only data that ever existed was, wow, whatever you download from the internet, I guess, fair game there, but it's whatever shipped with your app and whatever your app has created. It was a pretty simple model to keep in your head. [00:04:37] James: Yeah. And for my stream timer, the application that I have on windows and Mac, this is an application. The only application that I really create in which I am. Writing files to desk and having other applications read them. Now I do this, like if I use a monkey cash to cash documents, they're written to your storage, but it's the only time that I expose to my users. Where the files are written are important rights because it writes a file to a disk every second and updates this, this thing with the timestamp and, and other applications read this information. So I actually have to give the user this URL and, and when it sandbox, it's actually inside of an app container. So you can think of it almost if you're into the world of Dockers you're in this container, that container can't reach out. There's probably a way to do it. Um, but in this instance, right, it's really recommended to keep it in the container. So this has been fine, but then I had to use. [00:05:37] Frank: Well, it didn't want to do that. Let me interject. It's not fine, James. It was fine for you because you were writing one file per app or something. I somehow managed to always write apps that are file based on an operating system that hates files. Yeah. So I've been dealing with this thing since I was 3.2, when I really started circuit, it's been nasty since the beginning we'd even have the document picker. We didn't have the file picker before I had to write my own browsers and everything. That stayed within the sandbox, but then I would install libraries like Dropbox and, uh, Facebook and Microsoft, whatever. And they would integrate in, but I would still have to build my own UI is around that still working within the constraints of the sandbox and then figure out a cash, all that stuff. Uh, we're about to do a lot of complaining on this episode. I'm sure, but I want to put a little bit of in perspective and say file stuff has always been hard on iOS. And honestly, even with all the, all the complaining we're about to do for the next, who knows 10 hours, um, it's still, it's tiny bit better than it used to be a file access has just been terrible. [00:06:52] James: You know, and one thing that is, is nice. Uh, you mentioned some, some keywords earlier, some APIs that are available, the reason I've mostly been, have been able to get around. Actually understanding how the security model of file access works on these different platforms is because Google, apple, and windows have done a lot of this for me and the Donna team. Like if you just write a file into your applications of it just does it. It's like, yeah, you're a scoped. You're, you're fine. You're inside the container. [00:07:25] Frank: works. Unix works within your container, all your standard system IO. It works fine within your container. None of what we're about to talk about applies, just use that stuff. That's great. [00:07:37] James: Now, if you want to use, uh, you know, allow your users to pick a file or save a file or pick a folder, this also works very nice, Frank, because the document pickers and the share sheets and the folder pickers and the panels, all that stuff. They handle a lot of this for you under the hood. If you're like, I have this file, I want to write this file over there. Like it will do it for you. Like it handles the permissions because what has happened here, what I realized is that the operating systems that are in your apps in a sandbox, if you are giving your user permission to pay. Or re or choose or write a file to a specific location they've chosen the desktop. So what the operating system does is it says you're using one of our nice little helper things where you want to, you want to write a file over here? Oh, cool. Like we're going to allow the user to pick the location. Uh, of that file or pick that file and we will actually temporarily give your app, like blessing to access that location only for. Okay, but you don't know it doesn't then you just call the filed out, read or filed out. Right. Well, and you're good for [00:09:05] Frank: it. Perfect. Lots of caveats, but yes, absolutely. You know that, uh, that is the security model. The security model is you are not allowed to touch anything outside of your container, unless the user picks it literally clicks. And then you are given what is called a security scoped and S. Yeah. That's like a NSRL and anyone who's done, apple programming knows all your files, stuff is done with NSRL, that's kind of their file system abstraction. So think of it as a path, but in this case, it's more than just the path because it's carrying around the security token within it also. So I've seen some people make a mistake and they think just because they got the security. And Surl, but they can all sudden go read and write to that file path that may or may not work, honestly, depending on whether you happen to be on the UI thread at that same time and a few other things, but you are really not allowed to do that. What you're supposed to do is access the file through the URL itself. And so for that, it changes a little bit of application architecture because you actually have to keep this NSU around NS URL around in your. If you ever want to like open the file, read it, write it later, read it again, write it later. You're going to have to keep that NSRL around the path itself. Won't be enough because you need that security token. [00:10:32] James: Yeah, that's a good point. And there's still things that I'm learning, to be honest with you. Um, because in my testing. It's mostly been okay. But it also seems like sometimes it's not, [00:10:45] Frank: Nope. I promise you, there are very specific ways in which you're supposed to handle this. So when you get a security backed dynasty URL, you can query the NSRL to ask if it's security backed. It might've been be a property on it. It's definitely it's in there. It's like a key value store associated with every NSRL and it's in that key values. Inside of there and what you're supposed to do now, this is terrible. Can I tell you what you're supposed to do? And then I can tell you what you can minimally do. Here's what you're supposed to do, everyone. When you want to access the file that that URL points to you're supposed to start by calling a function. Start accessing security scoped resource. That signals to the operating system that, uh, not only do you have the security token, but you want to assert it, you're actually going to push you actually want to access that resource. This is the fun part. Now, now you're supposed to open an NS file present. You're supposed to signal to all other apps that you are now going to read this file. This is important because if the file let's say is on an iPad, but you're on a Mac and you're viewing it on the Mac, it might want to do a synchronization right then. So this file presenter is a signal to the operating system that we want to synchronize. Right now. So you have to do that very important change. Then you still can access the file. You now have to use an NS file manager and tell it exactly how you're going to access the file. Are you going to read to it? Are you going to write to it? Are you going to delete it? Blah, blah, blah, blah, blah. And then that will give you a second URL. And now you have the privilege to access that second year and then the operating system will take care of all the synchronization and everything else itself. Doesn't that sound wonderful. [00:12:35] James: Sounds ideal to me, Frank, that sounds like the, exactly what I want to do now, Frank though, you know, if I have these URLs, what happens if like the user closes my. [00:12:47] Frank: Oh, gosh. Oh gosh. Okay. That's a whole different, no, no. You're you're you're you're out of luck, buddy. The user has to go select the file again. It's impossible. What could you possibly? We do [00:12:58] James: incorrect Frank, because let me tell you, all you gotta do is take that NSRL data that you get back and turn it into something magical called a bookmark Frank, a book. [00:13:11] Frank: It's so magical just way to use the API. It's so magical, but I'm sorry. I just have to finish my long diatribe from before. I want to say the minimal thing that you should do, James is call those start accessing security scoped thing, and stop accessing security scope thing. That's minimally enough. And that'll guarantee that you actually have the permissions on the file when you actually want it. [00:13:35] James: That's what I'm doing currently. So right now I'm really lucky because Frank talked to me into using activities and S process activities properly. Wouldn't doing stuff with IDs and long running pro as a whole. We did a whole episode on this thing. I'm pretty sure anyways, this makes sure that the process doesn't fall asleep. So what's nice is, um, whenever I start these activities, I start, uh, You know, accessing the security scope resources. And when I stopped all of them, I stopped them. Cause you don't want to leak this precious Colonel resources, uh, Frank. Um, so that is what I'm doing in general to begin with. And so, so let me get back also to why I needed to do this, right, because forever I've just written. Data to the container. And that was completely fine. Like other applications. Yeah. Other applications can access that stuff. It's no big deal. Like other apps can get into your container. It's totally fine. It's especially if they're not sandbox, it's not a big deal. [00:14:44] Frank: Actually. If the user selects the file, if the user selects it, it's, that's the whole, it's not a whole, that's the way the security system [00:14:51] James: works. And in fact other applications require that you pick it. So it's great. Um, and to read this file, which is, which is really good. I had a user though, that was like, Hey, I don't want you to write to this file every second on my SSD, I want to put it on a secondary drive. [00:15:14] Frank: Okay. The came from, I use this video editing software. Um, it's really nice DaVinci resolve. Yeah, it's very nice. The problem is they've really screwed up their Mac security model. And every time I open it, it asks like six dialogues worth of can I access? Uh, volume, can I access a volume? Can I access a volume? So the O is, um, sometimes volumes have gotten their own weird security stuff and Mac 11 and 12. [00:15:43] James: And here's, what's interesting about that. Frank is I thought all I needed to do was add those special attributes into my info P list, but let me rest assure you that that doesn't matter at all. If the sandbox, because if your app is sandbox, none of that stuff matters because it's all security scope files. [00:16:03] Frank: Yup. Yup. Yup. Um, in some ways I think it's good. I never really liked your path. I think you always should have had a file picker if I'm honest. Um, but um, you were living the good life you were living on borrowed time. It was, it was just a matter of moments until you would have to implement this. [00:16:25] James: Yeah. And there's two routes that I could have gone as well. So actually inside of the security scope, um, bookmarking shenanigans, we haven't gotten to bookmarking yet, but inside the security scope stuff, you can, um, you can specify in your entitlements if you want, um, something called like app scoping or, um, document scoping. [00:16:47] Frank: Yeah, I'm sorry. I didn't mean to, I, I took a deep breath because oh my God, the details here are so complicated. Everyone go read the docs before you choose which one you want, but sorry, please continue. And I'll I'll fix whatever you said wrong. [00:17:00] James: Perfect. Great. Well, so from reading the documentation, really the app scoped bookmarking is, is, um, persisting access to a specific file or folder document. For only specific files. [00:17:20] Frank: Yep. You got it. You got it. Okay. So the problem we have w we're diving into bookmarking, I guess. So you have this, I know CRL, it's beautiful. It has a security scope. It's beautiful. The user selected it. We're good. But then the app crashes and you want to be able to access that file again. [00:17:35] James: So, great example of this is I was like, oh, this is going to, so this is what I thought, Frank. Oh, my goodness. Okay. This is super easy. I'm going to, I'm going to use the NS open panel or whatever it's called the NS panel, and it's going to be this beautiful picker and an async the way to fight it with task completion sorts. It was beautiful. It was like pop, pop, pop, pop. And I got back to this URL and I was like, this is great. I'm like, yeah, I have this URL. I test, I can write to it. I'm writing files, nonstop, Frank files, Wu files everywhere. And then I closed the app and I reopened it and it's like, No, I don't think so. No, bro, [00:18:12] Frank: no security for you. [00:18:14] James: Nope. That's because that security token that you talked about earlier, I know no longer valid. No, [00:18:22] Frank: no. How are you even saving it? Where are you saving the file path or what are you saving? The NSRL. [00:18:28] James: I was saving the, um, file. Ooh, great question. And I'm glad that you asked I was saving the, um, What was I saving? Oh, right here. It's here. It's here. I was saving the, the panel gives you a URL and I was saving the relative [00:18:48] Frank: path. Yeah. Yup. Can't do it because the path is just string. It doesn't carry any of the security tokens with it. Very unfortunate, sad frown face. So what you have to do is while your app is alive, you have to keep that NSCO RL around and in memory because you don't want to lose that security token. Uh, when, uh, you want to save that file way to be opened later, instead of saving the path, what you have to do is two steps. Create this thing called a bookmark, and then save that bookmark somewhere. And it's not actually too bad of a process. It's just a function sitting there on NSCR what does it even called? Like create bookmarkers something like bookmark. [00:19:33] James: Beautiful. You some NSA data back. [00:19:35] Frank: Yeah. And if you haven't used an estate of before, it's just a byte array. It's just a fancy name for a biter, right? So it gives you a hunk. It gives you a bunch of bites back. You got to save those bites somewhere. They're not a string though, so you need to save them away in a binary format or something like that. You could convert it to say 64 or something. If you're being crazy. The tricky part now is when you want to get that NSRL back. You got to go get those bites. Put them in an NS data, and then you can rehydrate bring back that NSRL from that book, mark data, it's not too bad of a process. So did you get that far? Did you enjoy it? [00:20:16] James: I did get that far. Yes. So the things that I do well, so the documentation, I love the doc. I love apple because Apple's like they go in here and they're like, um, You know, well, they're like the app, the app scope, bookmark, like let's say your app employees, a process where you download stuff and you use an NSA open panel. I'm like, I'm with you. I'm dumb dude. And you want to save stuff to a specific folder. I'm like that. Yeah. That's what I want to do. Apple it's [00:20:48] James: like then create an app scope bookmark for the folder and store it as part of the apps configuration. I'm like, that's cool. And they're like, perhaps Projet bar perhaps. You would save this in NS user default, who [00:21:01] Frank: knows, maybe you put those bites wherever [00:21:07] James: you want, and then you put them wherever you want. And then it says with the apps go bookmark, you can, uh, the app can obtain future access to the folder and that's it. So I've done that. And I shove all the data into NS user, all the NS user defaults, shove it in there. [00:21:26] Frank: It's probably fine. I forget how big it is, but I think it comes out around 500 bytes or something. It's not that big. So you can put it a lot of different. They recommend [00:21:36] James: they recommend it, Frank, and you can shove just an NS data blob into Ennis, into standard user defaults. Like you just shove it [00:21:45] Frank: and you just opened up a rat's nest. Like you won't believe because you mentioned the, the naughty word folder. Uh, the rules for how you access folders and files while very similar, have wonderful little deviations from each other and all that kind of stuff. So let me. Let's pretend we've just been talking about files, but now let's talk about folders for a moment. So this is important to me because if I want someone to open a solution and say continuous, so let's say they're in their favorite, get editor on an iPad and they see a SLI and file, and they're like, Ooh, I want to use Frank's app to go edit that file. That sounds. They click that file. They share it with my app. You can do that. I calls open URL. You get in an NCRO, all these security things apply. The thing is I only have access to that file. At that point, I do not have a security token for the folder it's in or any of the sub folders or anything like that. And so what my app has to do is check if it's ever gotten a bookmark for that folder before, and then it has to. Pop up a dialogue and explain to the poor, poor user look, I'm sorry. I get it. You're opening a solution file, but I'm going to have to ask you now to open the folder that contains the solution file. Super embarrassed, frown emoji, but security moving on. So I have to do that because I want the nice thing about a folder is once you have security access to a folder, you could get everything inside that. [00:23:24] James: Yes. That is correct. That is the nice thing about [00:23:27] Frank: that with one more caveat, uh, all those things still have to be accessed through NSRL while most importantly, though, you still have to call that start accessing security scope thing on the folder. Not on the files, but the folder, [00:23:42] James: correct? Yeah, because the user has picked that's important part. It's what the user remember that's your, your scope is what did you let them know? You can use NS open. And you can specify if they can pick multiple files, a single file or a folder. Right. So I say you can only pick a folder and go to town there basically [00:24:03] Frank: folder. Okay. I didn't know that I thought you were doing files, but that makes sense. Cause you have multiple timers, I guess they can go simultaneous. [00:24:10] James: Yeah, because I write like five or six files inside of there. And then additionally, how I, how I check to see if you have write permission. Attempt to write a file to the fight game attempt. Does it work out good? [00:24:25] Frank: Well, we didn't bring up one more lovely little detail. So you've created a bookmark. You threw it somewhere. Who knows? Now you brought the bites back. Now you tried to create a URL from it. That operation is. Uh, it's right in the docks. Um, when you try to rehydrate those bites, you could get a Knoll and Surl back. And at that point, um, there is actually a nice little function. You can say, like re request or something like that. It'll try to update the security token that can also fail. If that fails, then it's up to you to present user interface to the user and be like, hashtag super sorry, but I need you to go pick that folder again. [00:25:07] James: Yeah. That is I'm in the early days. So I have not done some of that yet. So right now I try catch and do nothing, which is not ideal. Nope. [00:25:20] Frank: It will happen because here's, what's actually super cool about the I'm sorry if I just stepped on you, but I'm no. The best part of these bookmarks is that because they work outside of the sandbox, it's up to apple and apple servers to track them. And what's neat is let's say a get app serves me that one file and maybe the person moves that file around within the directories or something, or even, I don't know, device to device, all that stuff, all that sinking. My bookmark to that file. It not only contains the security scope, but enough information to apple to know how to go find that file. So if the file came from an iPad, but I'm accessing it on the Mac, that's totally fine. Uh, apple will deal with all the translations and everything. That's, what's kind of super nice about the bookmarks too, is that once the user has selected the file and as long as it keeps hydrating, um, it can handle the file moving around. [00:26:20] James: That's true. Yeah. I actually had it where I deleted the folder and then I created a new folder and it still worked because it's like, oh, it's still the, it's the same. Oh, that's [00:26:30] Frank: interesting. I don't fully know all the rules, you know, I can remember like really delete a folder. I'm like, yeah. How much, how much tracking does it do [00:26:40] James: now, Frank, I've got to mention one more thing. Cause you forgot one of the most important aspects of, of creating and getting the bookmark. Wait, [00:26:49] Frank: wait, wait. Okay. I'm trying to, I'm trying to get ahead of you. I can't do it. I can't do it. Okay. I got, I got [00:26:56] James: the, I got the. Right. I got the data, I get the bookmark data. And then that gives me a URL. Now that could error that could give me an error, but it can also give me one more thing. Frank, do you know what that thing could be [00:27:11] Frank: cited? I, now I'm worried if I'm handling this thing, so you better say something. I know, uh, give it to me. [00:27:18] James: Well, there's a nice out VAR that you pass it, which is a Boolean flag that tells you if it is still. [00:27:26] Frank: Right, right. Um, I think I might've got confused. I thought it returned all, uh, for the stale one. So it's the bullying. Yeah. That's what's important. Um, so for the stale, [00:27:38] James: it might return, you know, by the way, who knows that? There's, I'm [00:27:41] Frank: sure it's apple. They'd love to know. So catch that one also. Um, so does stale mean that you can re request access or the stale mean you have to present to the user, right. [00:27:53] James: No. So in that instance, you, you request to make new bookmark data. Now I don't actually know what you do cause there's, there's, there's literally an out VAR is stale out VAR error and NSA error. Like I don't actually know if you do, if it's an error, I think the error means you need to prompt them to repack it. [00:28:11] Frank: Yeah. All they're saying is your data bytes need to be updated. Yeah. You, you have old data bytes. Like the files they're still there. Security permissions are all still good. They just want you to update your bites. They just want you to update your bookmark data. Yeah. That's it. So that's good. Now, now that you, now that I've recalled all that stuff, so that's nice because you still have access to the URL at that point. Yeah. [00:28:40] James: There is can't get easier than that, right? No. Yeah. And [00:28:46] Frank: you're not even going through in his file manager. I love it. Your name [00:28:50] James: now. I'm not in general. Yeah. So, okay. Here's here's what it says. I'm in the, I love objective. See the, you are the URL by resolving bookmark data options relative to URL. Bookmark Dale is stale air yep. Instance type. So. Um, what's nice here. So his tail is on return of yes. The bookmark data is stale. Your abstract create a new bookmark using the returned URL. So it'll return you a URL, but it's not good. And use it in place of any sort of copies of the existing bookmark and then air. It says the air that occurred in the case of the URL. Don't tell you what to do, but it's definitely, there's an area. Yeah. [00:29:29] Frank: Yeah. If it's an error, your app has to make the logical choice of can I live without this URL or do I have to prompt, but you start [00:29:36] James: again. Yeah. So what you need to do is you need to say, get the URL. If it's an air, do something, but if it's stale, create a new bookmark data store, that bookmark data, and then. Well, at that point, you don't really need to get the bookmark data back, but you might as well get it. Get a new URL from [00:29:56] Frank: give you a new URL. You are supposed to recreate the bookmark data. [00:30:01] James: Oh, that's right. Yeah. Sorry. Yeah. You're right. So here's the flow that I have, which here's my flow. Go see if there's bookmark data available. Right. So if there is no bookmark data bytes, just bytes. Cause if there is none, then there's soaring in the default location. I don't care. But try to then. The NSRL from the bookmark data. Now, if that is stale, take that stale URL. Go create new bookmark data store that bookmark data in NS user defaults, and then get a new NSRL from that bookmark data. [00:30:39] Frank: No, you don't want to new, but the one that returns you, it should be. [00:30:46] James: No, it doesn't because here's the thing. If it's stale, Frank, you need to use the stale one to create new bookmark data that does not update the URL. You need to go. A new URL from the newly created bookmarklet. Yeah, it's totally true. Frank, I'm going [00:31:04] Frank: to agree with you only because I haven't done it in two years. I don't remember all the details. So it sounds a little fishy, but I'd have to read the docs again and I'm not going to do that. [00:31:16] James: Nope. And then you can start accessing security, scuffed resources, and Frank, you can go look at my data lines. 1 33 to one 40. That's right. I don't trendlines. It's not great code at all. It doesn't even, it doesn't try as much goes to town, but, um, yeah, so that's sort of the that's what's happening in my code, Frank and it's gross now, now, now here's the thing. You mentioned something earlier, maybe this is my problem is I also. Do not [00:31:47] Frank: James, can I just read you from the apple docs? Oh my gosh. Oh God. Okay. Don't be sure if it's stale, the bookmark data is stale. Your app should create a new bookmark using the returned URL. Yeah. Yeah. I said that. Okay. Maybe we were miscommunicating. [00:32:05] James: Oh, but you think that the, you, oh, you think that the URL. It's still valid with the state, from the Euphrates I'm [00:32:13] Frank: telling you is to go update your data bytes. That's all they're telling you. The URL should still be good at that point that they give you, but they want you to update your data points. And I think somewhere, even deeper in the docs, they explained this happens when a file moves, basically. [00:32:30] James: Yeah, let me, yeah. Now, um, one thing I'm not doing is I am still using filed. Right. All text. I'm not using an S file manager. [00:32:44] Frank: Yeah, you can get away with that. It's okay. Uh, the places where that's harmful are when you're on like an iCloud drive or a Dropbox on one of the sinky ones, but even then, honestly, you can get away with a lot, if the files aren't too huge or anything like that. Yeah. You really should. He was an NFL manager, but I get it. I don't do it all the time. One thing to absolutely watch out for. As the NSU or ELLs that the operating system will give you in the various file pickers document pickers, open panels, drag, and drop. We haven't mentioned drag and drop and as URLs can come from drag and drop from open URL, they can come from so many different places. Trust that URL dot path or dot file path is an any way a valid file path. It might actually be the text. This is not a file. It's not guaranteed. If you actually need a path, the path like something that you want to store as a string. And again, This is the path you would use if you're using system.io. So it's important. What you have to make sure you say is either URL dot file, URL dot path or dot file path one. Not all of them actually resolve to an operating system path. [00:34:07] James: I've found that relative path seems to resolve correctly. [00:34:11] Frank: Okay, but be careful because I had a lot of assumptions and then I did drag and drop. And the URLs they give you are crazy. The most sure-fire way I've found is whatever your URL is. Dot file URL dot path. That's kind of the most guaranteed. But mine has a folder. It doesn't matter in this case. Yeah. All, all NSCR. I know it's poorly named, uh, the only thing that distinguishes in the URL world is there is yet another key value property on a new, your all same, whether it's a folder or not. And they handle that translation. [00:34:47] James: Yeah, anyways, this is my life and I hate it. And I'm [00:34:52] Frank: throwing an IDE that wants to randomly access files anywhere. That's [00:34:57] James: the problem now. And the other problem I have Frank is testing this. So let me get back to one of the things I tweeted. And you were, you were the only one that responded, but it seems terrible. So now let's say I'm running my application under debug. Like I'm just, I'm in vs for Mac I'm in X code. I'm just sitting in debug, right? I'm sad. This is great. Here's the thing is when you say, Hey, give me the default. You're not sandbox at that point. So it's like, Hey, here's the document folder. Everything works that you need to, and in fact, you need to have those permissions in the folder so they can pop up and say, Hey, do you really actually on Mac? You don't need them, but if you want to create a string to display, you can do that. But if you try to go right to the, um, uh, a network attached storage, or let's say an external drive, it'll pop up the permission. We'll do it for. So to test sandbox, you have to be in sandbox and Frank, here's what I've been doing. And you can tell me how wrong this is is I write all my code. I imagine that it's work. I, I imagine that it's working, I bundle it up. I archive it. I send it to, um, or connect via transporter and then I suck it down. 10 minutes later via TestFlight after I delete my OBJ file. So it doesn't think I have it installed, then I'm sandboxed and I can test it correctly. That's my, that's what I've been [00:36:23] Frank: doing. I want to preface everything I'm about to say with, I love how you abuse. I, I mean, uh, uh, whatever test flight. I love that James you're, you're a role model. I'm always like, I should be nice to the apple servers and you're just all like, Nope, changed a line of code, better upload a new one. [00:36:44] James: Give me a new. [00:36:45] Frank: No, no, it's all easier than that, James. It's actually just like iOS development. What you have to do is go register your Mac up at the profiles thing and you have to get a Mac development signing certificate, actually, nowadays that's all easier. You can still just use your apple signing certificate. They find out what you know. You have to create an app ID for your app. Hopefully you've already done that. You have to create a provisioning profile, a developer provisioning profile, not a distribution one, and associate your computer with that. You must then download site provisioning profile and install it. You double click and it installs. Now you are all set. You can go into visual studio, quickly, click tell it whatever search you used, whatever profile you used, and you are good to go. The debugger actually runs just fine inside of the sandbox box. It's not an issue at all. And truth is I never do it. I'm testing the sandbox. I kind of reserved for. Weeks where I test the sandbox, but there are apps where there are just fundamental parts of the app that I couldn't use without actually being in the sandbox. And so you have to go through all of those steps. It's terrible, but you're honestly pretty used to it from iOS. So it's fine. [00:38:16] James: That's true. That makes sense. Because, well, that's the funky part, right? It's like you're, if you're on a simulator, you can't really get in the sandbox. You need to put on a device to get in the Sam. [00:38:26] Frank: That's true too. But the simulator has at least like its own weird folders and everything that are true, not where they would normally be, but you're right on the Mac. When you're outside of the sandbox and you asked for the documents folder accuse you of a user's documents folder. It's scary. I don't want that. I am so used to actually to iOS that it freaked me out the first time I saw that. So I would say it is actually worth, um, doing development in the sandbox as. Tiny itsy-bitsy amount of time to the compile time. Um, but at least then you're sure that like all the networking you're doing is right. It guarantees that you get your entitlements, right. It's the worst thing trying to debug and titled errors. Um, yeah, from builds. I should also say. Some of the things that we discussed actually require a few entitlements. Like there is an entitlement on Mac to allow, um, security to files that the user picks. And I'm not sure if that's on by default. So you might want to check box in the entitlements. There is also a full disc access entitlement that you can check. But, um, I've never tried to get an app approved with that and I I've really considered it for continuous. Uh, it's not allowed on iOS. So throw that thought away, but on Mac, I guess they approved some apps with it. Who knows? [00:39:47] James: Yeah. So the entitlements there, so there are a few that you need to know about. By the way there's an entitlement called app sandbox. And that's actually on by default, when you create a new app, then there's another one which I believe is on by diva. I didn't add this one. So it must have been by the default template, but it's user files, user selected. Read-write that ones. Um, [00:40:10] Frank: yeah, and I only bring it up because I believe like the F sharp template is missing it. And I'm always like shocked. I'm like, why isn't this working, uh, security. Um, [00:40:19] James: and then this other one is you need to add the app scope or the document scope that we talked about earlier, true or false into your entitlements. Which are important. You need to add those in there. Um, funnily enough, at some point they stopped requiring them and then they started requiring them again. [00:40:35] Frank: Um, even, yeah, even more details to a, you're not doing iOS, but there's even more to it. Um, the way the document picker. Work is different, depending on what's on your info P list file specifically, there is, uh, an option of whether you can open documents in place. That's kind of, uh, the words to go check for and the info key list. And what you want is if you, if you check that, then you'll be able to do all the stuff we've been talking about in this episode, all the security stuff, the bookmarking, all that it works. So go turn that on. Alternatively. Um, if you don't want that, what happens is you can still use those dialogues, but apple copies the file into your container and then gives you a URL to that copied version of the file. So it's a really important distinction to have. Um, so that is controlled primarily through the info P lists. But even when you open the file picker, you can tell it, uh, whether to, I believe they call it import whether to import this file or whether you're going to attempt to open it in place. If you import it, it comes into your container in place means you get one of these security scoped and SCRs. Yeah. [00:41:54] James: That makes sense. Yeah. And the full. Read access stuff. Um, I, I'm pretty sure they really, really, really, really, really, really, really, really, really don't want you to do that. I had a discussion with an apple tester about that specifically because I, before I learned all about this stuff, I was really confused. Cause I was debugging. I was a normal mode and I didn't understand. About the security scope. So I thought when I was debugging, I was like, well, I get a pop-up about documents, removable storage. And, and even in my documentation, I have like, just give me, like, you can add any application to have full district access, but it doesn't matter if the app doesn't request and it's not approved by apple. It's just, it's ignored because it's not in the entitlements. So I had an error message. I didn't [00:42:41] Frank: know that fun fact [00:42:42] James: fun fact. Yeah. It doesn't matter. 'cause that's the thing is I told the person on the GitHub issue, I said, oh, just give me full access. And he's like, it doesn't work. I was like, oh yeah, fascinating. I would've thought [00:42:53] Frank: because I didn't know. Thank your [00:42:56] James: app is your app is not entitled fun fact. Now, if you're debugging locally, And you're not in sandbox mode. I'm like, oh, this is all this stuff. So I had to put a little error message that said, oh, you don't have access to this folder, go give full disc access. And then the apple tester was like, and let me refer you to segment four section 18, paragraph two of the apple guidelines that sandbox apps may not, blah, blah, blah, blah, blah. Except for these all like, oh crap. Okay. Verbiage. So I think you can do it, but I think it's one of those rare edge cases where they're like, I don't know. [00:43:31] Frank: Yeah. Uh, but let's put it this way. I was willing to learn all this crazy NSRL security stuff. Just to avoid that conversation with apple support. Plus, I didn't want to break the security model, although it's a pain in the butt to use. I think when we opened the show with both Mike the sandbox, um, it causes me a lot of consternation and there's. Apps. That would be a lot easier to write without it, but overall it's a good, it's a good thing for the industry and all that. I do believe that. Yeah. So, um, yeah, whatever deal. [00:44:08] James: No, I, I, you know, learning these things to me are. Fun ish. And now, now that I know it, I'm like, okay, like I definitely now can go off and figure out how to do this thing. It is a little bit of that native code that you have to write and get in there and things like that. But, um, yeah, I'm, I'm pretty happy with how it is right now. I need to do some more testing. I did get someone that the person in test flight, so the person actively is testing it, which is kinda cool. Yeah. I was like, Hey, sorry, I'm going to test all the bits in this. And they found a bug already with it, which I'm not sure, probably. Cause I'm not using NS file manager, which by the way is not a great API. Let me just tell you one. [00:44:52] Frank: No, it's confusing too. Every time I use it, you, you, it takes like an of what you want to do to that file. And it's so confusing. I have to read the docs every time. What were you going to complain about? [00:45:05] James: The method to delete a file is called remove, and it just bugs the crap out of me. So Unix [00:45:12] Frank: C. [00:45:13] James: RM remove anyways, that's going to do it for this week's podcast. If you made it this far one, you're a hero too. We're going to be celebrating our 300th podcasts and you can participate live. We will be live streaming on my YouTube, but additionally, you can send in a video, a snippet, a question, a topic, anything by going to merge conflict that FM hitting the contact button, you can drop us a link to anywhere those files are located. And let us know, um, what you wanna do. We'll be playing back. Some of those clips if selected, live on the podcast. So you have a few weeks right in, go do the thing. We'd appreciate it. Go to merge conflict out of em, tweeted us on the Twitters and do all the things, but that is going to do it for this week. Episode sounds I'll next time. I'm James Monson Magno and I'm Frank Krueger. Thanks for listening.