mergeconflict223 James: [00:00:00] all right, Frank, we got some listener feedback questions today that are going to drive the entire topic. Can you believe Frank: [00:00:15] it? Oh, I actually really love these what we're, we're always kind of begging at the end for a few topic ideas. So it's always good when something interesting comes in and we want to talk about, so I'm all about it, man. Let's do this. Let's do some listener questions. James: [00:00:30] Yeah. That's of course merge conflict at IFM. There is a contact button you can email us like Gary did, and we appreciate it. Gary, Gary Myers, he wrote in and said, Two or there's really two questions. So we're going to break it down. And the second one is pretty short. I believe that we can kind of summarize the, do want to answer. I don't want to wait. I want to have Gary wait, 10 more episodes for lightening talks. I want to get to Gary's question, but the first one is very fascinating. It reminds me of the very first time I wrote an iOS or Android application coming from windows. Um, I had, uh, I worked with a team, my friend, Jesse, that works at Twitch. Now I talk about them all the time on the podcast. He literally worked in Canon and he was our installer developer. Like all he did. Was installer stuff like everything, you know what I mean? Frank: [00:01:21] Yeah. Yeah. I totally know what you mean because I wish I had someone working for me that did that. I have one app that I have to maintain and installer with. And it's too much because you think like, Oh, and installer, that's such an easy little app to write, but no, it takes a lot of engineering effort. It turns out. So that's pretty cool. It was Canon. Then they actually had a proper, uh, uh, installer engineer. James: [00:01:45] Yeah. Proper installer engineer. So he did the entire sort of new as MSI or Wix or whatever, the different they changed it. But you know, when you were installing this huge application, it was laying down, you know, net framework versions, it was installing database scripts. It was running upgrade. Scripts is doing all sorts of crazy things. And I remember the first time I wrote a mobile application, I was like, I just, I just put this file over here and I upload that and I'm done and sure enough, I was. And that's really what Gary's question comes down to. He says, and I read, I haven't yet seen any documentation about what is involved and permitted. I should say when updating an iOS app from one version to another, for example, Um, we're still not sure what this means, but we're gonna try to break it down. He says, in what language, our schema changes, um, written and executed is file and directory copying and creation possible. Can we inquire about the user's device and branch the update code based on their hardware and iOS version, et cetera, so that it would be great. If you can make an episode or just give me the documentation. No, we've refused Gary to give you documentation and we are going to make it all up. Um, Off the top of our heads because we've been doing it for 10 years. So hopefully Frank, we know. Aye. Aye, aye. Aye, aye. You know, I click a button on my iPhone and I see the little bar bup, bup, bup, and it's updated. I imagine in that time that what has happened. From knowing how I package up an iOS application works is that it does, it did one to two things. I'm actually not sure what it does. So one of two things could have happened. I think that when I up, when my app updates from the app store it either uninstalls. And then reinstalls or it basically X copies in and overrides and just like plops it down. Just like here's a big, here's a bunch of globally goo of stuff. And it's like, here it is. Um, and that's it. That's what I imagine it is. Yeah. Frank: [00:03:48] As far as I know, that's all it is too. I actually really love that question because it is one of those things that doesn't really make it into documentation. For some reason, it's like, well, what does happen when I update my app? So, you know, you write an app and you're storing user data and. If you're like me, you're storing data kind of everywhere, a little bit in the cloud, a little bit. And the user preferences and a little bit, and the file system and in the file system for different reasons, some of it could be persistent user data. That's actually really important. Other bits can just be. Cash stuff that, you know, you're just keeping around because you don't want to re download it again. And as far as I know, just like what you said, if you have an established app, uh, these are. I almost call them Mac apps, but they're not Mac yet, but their dot apps, you know, they're the little directory called the.app. And as far as I know, it's just a little file system magic where it's not actually ex copying over the old app, but it's more like two pointers swapping. So it just kinda like magically flips your, a new code into place. Now the big difference is so you're. Your app itself, you can think of that as a hundred percent replacement from the old one, the old one doesn't exist anymore. However, on iOS, some things do persist and those are your NS user defaults, or at least the standard ones. And those are your documents, directory. And. That's about it, your key chain. All so yeah. Okay. What am I forgetting? Is there more, James: [00:05:32] um, so, so in your let's, let's make it very clear. So NSUs defaults to these are your preferences. Um, if you're using an exam in essentials or, you know, in Android, these are called preferences as well. And these are bullying's strings integers. These are your settings of your application that are there. And then those are, those are stored in a, in a magic area that is persistent and often, sometimes backed up by the iOS system itself. And then the files, Frank: [00:06:01] right. I'm sorry, I just want to interrupt you because they're guaranteed to be backed up. It's actually really important because you kind of rely on that. At least I rely on that in my apps where I don't have cloud backups for everyone's data. So I'm like, Don't install, don't install the app because if you uninstall the app, that will actually delete all that data. James: [00:06:21] Correct? Correct. Yeah. Now the other part though, is that file system in this file system, there's a bunch of different directories and this, this should be a, this is also very fascinating cause hash directory, there is your library, your, your document directory, and each of those are versus at a little bit different from my understanding. You really don't need to worry about anything unless you're putting it in the temper cash directory, because. By nature of a cash or temp directory. It is a directory that is temporary and should not be, should not be perceived as important to be there at all times. So it is possible that a temporary or cash directory is removed. If the user has a low memory, they're updating an operating system or even updating your application, it can be purged if you will. But you're going to store not only files there we might be, have might be saving your database. Directory is right. I guess also, if you used. What is the builtin iOS, um, database, Frank: [00:07:20] uh, core data. I think you're thinking of, James: [00:07:23] is that a file? Is that stored somewhere different? I've never used it. I don't know if anyone should, uh, Frank: [00:07:29] as far as I know, um, cloud data or sorry, cloud at core data has a few modes. One is the cloud, so there's an iCloud version of core data, but another version of it is SQL Lite database. So that would be a file just sitting on your file system. Yeah. And I just said the pink elephant in the room, SQL Lite. It's a great place to put all your data monkey cash uses it. And that goes on the file system. The cool thing about that is when you update your app your day, the base will still be sitting there waiting for you. James: [00:08:04] Yes. That's correct. Yeah. That's my understanding of it in general. And so if you're like, Oh, I'm updating and aye. Aye, aye. Expect this file to be there. When I update it, it will be there. But of course, if it's a fresh install, it wouldn't be there. So, you know, your logic is going to be there. Like, did this file existed and not existed? This setting existed did not exist. Like, you know, did my user register or not for my application. Um, it's seamless in that experience. Frank: [00:08:31] Right. And all of my apps, just as a kind of design purpose, I've always tried to manufacture ways for people to get the data out of the app kind of easily. Because even though we, as app developers have access to that documents directory, it's not always easily accessed from the, by the user. So you have in your info P list, you can say that people can access their documents, directory via iTunes. Have you ever used that file interface? The iTunes file interface, James: [00:09:01] um, use the new files picker. Frank: [00:09:04] Not that, James: [00:09:04] not that I have not. I have Frank: [00:09:06] not. This is like you go into iTunes, you plug your phone in with a USB cable, like it's 1990 and then, uh, There's a tiny little window that acts like a finder, but it's really broken. It's really bad. So that was the state of the art for many years. Now, there's finally a flag where you can say expose your apps, files to the files app. Uh, the one running on iOS. And I liked that a lot, cause it gives really easy access to your data. Yeah. If you're putting a lot of data onto the documents, directory. And it's useful data to the user data they might want to move around. You should really consider enabling that files app flag. I forget what the there's, there's like a couple info P list ones, one of them, something along the lines of share documents with files app. James: [00:10:01] That makes sense. That makes sense. And so when we think about the database, though, I want to make sure that people are aware that, you know, in, in most instances there's usually not a lot of things. You, you need to worry about there, but if you do have a database based on and whatever database you're using, there could be instances in which you change the schema of your database, if you will. So I recommend, never change. I recommend never changing ever. Right. And there's, there's not like migrations. I don't really know of something that uses migrations for mobile applications, similar to entity framework. Like that's not really a, there's not really a concept. Right? Am I wrong? No. Frank: [00:10:41] Completely wrong. Yeah. SQL Lite dash net man. Automatic migrations. James: [00:10:45] I mean sure. But I mean, as far as having to generate a migration file, you know what I mean? That's what I'm thinking Frank: [00:10:51] of. Yeah. I don't know anyone who does that. Of course you can do it yourself because that. That is kind of just good practice in the database world to be able to go up and down in your database schema version. So if you're coming from the web or server world, and that's what you're used to go for it, you know, there's, there's no reason to be yeah. Bad program around mobile. It's not like a performance issue or anything there, but I I'm too lazy to write those up and down scripts. So I just wrote a library that does it automatically. James: [00:11:20] Yeah, so SQL SQL dash net. If I add things, if I remove things as that work too, as I am assuming I can't change data types, that would be bad. Frank: [00:11:30] Well, you know, there's some principles with databases, you know, it's a relational database. So if you want to add data, You should probably be adding tables. Don't really be adding columns to tables and just relate it back to the other tables. So in some ways, if you're following first normal form databases, expand forever without you having to modify the old tables, you just ignore the old table. You know, it's not a big deal. Uh, so now I don't, I just chose the policy of not deleting. Columns, because that just seemed a little bit dangerous for a general purpose library to be doing. And if you are actually concerned about that stuff, that's where writing your own migration scripts is probably useful. But I guess to make the broad point that's on you, unfortunately you have to do that in your app. Yeah. I James: [00:12:20] remember back when I did windows phone development is before it used SQL light to use something else I forget, but you had to do. Migrations manually. And I would, I would have, like, if I'm on this version, go upgrade and add this column to all the things. Again, I could have just on the relational thing, but that was very, I haven't done that in a long time where I've worried about it because I've done best practices. Like you're saying where I'm like, Oh, I'm adding an RSVP function. So now I'm just going to add another table it's called RSVP. And then, you know, do that. Um, and even so I'd always add to data structures and just obviously program in. The notion that something could, um, not have it, right. So it could come back as the default property or Nall or something like that. So as long as you're calculating in into that, that Hey user from a year ago is upgrading to version two. I want to make sure that the data structures in version two are compatible with version one and that sort of general programming, and that doesn't go away in mobile necessarily. Frank: [00:13:25] Right. Absolutely. And so it's a little bit nerve wracking. I'll be honest so that whenever you're releasing an app and you have to do a schema change like that, I did a big change where the first versions of ice circuit, it was saving all the individual circuits and a database is just, you know, rows and a table. Which is great, you know, um, I use a database because in the old, old days, apps would just crash all the time. Not because you're a bad programmer, but the operating system would just kill your app, but just random moments. Cause it was mean, and you didn't want to be in the middle of writing a file or something. So it was just much safer to do everything with databases. And I still think that a bit today, I still feel like the operating system can kill my app at anytime. Anyway. I did this migration where. Instead of database stuff. I wanted actual files again. So I had to read the database, pull out all the rows, create files for them. Do that once and do that perfectly correct. A what if it crashes in the middle of that? What if it comes up a second time? I didn't want Duke. Of, you know, the migration out of the database into the file system. So that was a nerve wracking update. Like, you know, these updates, aren't always smooth and easy. Fortunately, that one actually went smooth. I was completely freaked out about it because that was all the user's data. That was the most important part of the app. And I didn't want to lose it. And somehow I made it through that migration. So yeah. I know it can feel a little intimidating when you change that kind of stuff. Um, test, test, test, and phased releases. So you don't get the story everyone's data all at once. James: [00:15:14] Yeah. And a good practice too, is you could also back up that database, right. Just make a dot back and then it's there. Then you could, you could even figure out some, some things in that regard, too. Just depends on how long you want to keep that logic in your application and keep it around. Um, cause you know, it's, they're sort of there, but one thing I want to make clear here is that talking about database upgrades, we're talking about migrating from a database to file system. You know, in this question he specifically asks, you know, when is it written? When is it executed? Can I access file directory? I'll make this clear and you can correct me if I'm wrong. You developer, any developer does not have hooks into knowing when your application is being installed or upgraded at all you these scripts, when your application launches the next time. Frank: [00:16:13] Yeah. And that's what made my upgrade so scary is that you can only run, you can only run your updates scripts when your app runs. And that means your app's going to run a billion times. That means you've got to detect that first run yourself. So you have to, if you're in a database, read the database version and do the migration at the correct time. If you're in my case, you have to read the file system and do those things at the correct time. So as far as I know, you're absolutely right. You have no knowledge of that while you were saying that. I kept thinking, like, I wonder if you ever get. Uh, in NSRL open context from running out of the app store or something like that, but that would be super fragile logic. So the general rule is no, you are not told when you've been updated. So your app has to have the smarts to figure out if it needs to update itself. And if so to do all that stuff. James: [00:17:13] Yeah. I'm trying to think too, if. There is an intent on Android. I don't think so. Maybe there is an. Oh, man. There's so many Frank: [00:17:27] wondering, like with validation, but even then, all that's telling you is whether they installed the app. Not whether it's been upgraded in place. James: [00:17:36] Yeah. Frank: [00:17:38] You would have to write a file, like a magic file that has the version number of your app. And then you can read that version number, but see, I've done that before and it doesn't work well because people inevitably update their phone or they buy a new iPad and you lose that file. So. It's tough. It's honestly tough. I hate data. James: [00:17:58] Yeah. The intents from Android, you, you can put an, an intent that says like when my application, um, Like when, if, if it gets closed or if it gets, you know, there's, there's some things like when it comes back, like almost like when the devices turned on, they've really lock that stuff down as of recently. And again, I don't think that necessarily, that would be a good experience. So ideally you may even build an, a, a UI experience into this. Welcome to version 2.0, we're making an upgrade, right. Make it a. The user taps on the thing, they got to wait for a thing that that's a valid option based on how big a migration it is, uh, instead of just it launches and then you do something and the user has to, you know, wait around for it. I don't, I can't really think of a app in recent history that has done that, but I have to imagine the things that we're talking about doing happen all the time in our applications that we're Frank: [00:18:52] updating. Oh, they absolutely do. So that means you don't use the Dropbox app. Huh? James: [00:18:57] No, no, I do Frank: [00:18:58] not. You open the Dropbox app up and it tells you we're updating the database, buddy. You better just get yourself a cup of coffee. We're going to be here while we're going to put a little spinner up. I actually completely agree with you. Um, when I did my eye circuit migration, I told her you should have done that just because of the possibility for failure and that kind of stuff. Uh, I would say. If you do that on every update of the app, I'm going to get super annoyed, just like with Dropbox because that's inappropriate, but totes dude. Oh my God. Those people are updating their database schema. Every version it seems like I try to provide smoother app experiences like the Apple model with. This kind of stuff is generally data doesn't exist. We just magically memorize all this stuff for you. And you don't want to bother the user with the inanities of managing data. Yeah. Except if it's appropriate for your app, like continuous, um, programming is all about file management. So I bring files right up to the foreground and pretty much put you in control of the documents, directory, because that's appropriate for that app. Other apps. I totally just try to hide the fact that they have data. Well James: [00:20:11] talking about data. Let's take a quick break and thank our amazing sponsor this week. Kalka that's right. Your assemble calculator. It's the text editor, right? That loves math and gives you the answers as you type it. Listen, do you love math? Do you love calculations? Do you love things that are built by Frank Kruger? Well, you need to get yourself a copy of it. Calca go to calca.io. It is one of the best yeah. Applications I've ever installed on all of my devices in the history of mankind. It is simply spectacular. If you're a data nearby me, it's powered enough for scientists and engineers or not just like me. I'm not really a scientist or an engineer. I'm a manager, but it really lets me do really cool things. Like my finances, my, my mortgage payments, my rent payments, all that stuff. It gives me really cool syntax. I can do go to Calcutta at IO to find out how you can download today for iOS, Mac or windows, desktop. Thanks Frank Krueger for sponsoring this week's vide. Frank: [00:21:09] Thanks for Krueger. Thanks Coca Oh Kruger system. It was written really showing up the money for the ads. James: [00:21:16] They have copyright 2018 on that website. You know, they're really putting the work in, uh, Frank: [00:21:21] just updated those apps. Give me a break James: [00:21:23] anyway, Frank: [00:21:24] websites too. James: [00:21:25] So let's talk about, so let's talk about the next thing, which I think is fascinating is, is, you know, There's a lot of different devices on here. The next question that he inquires about is are we, as developers able to inquire about the user's device in this is a fascinating question and branch the update code based on their hardware and iOS version. And now, Frank, I can not think of an instance in which I would need to branch my update code for the hardware iOS version. Like. That I don't think that that's a thing you need to be concerned about. Have you, is, is it a thing that we ever need to be concerned about? Frank: [00:22:01] I do a constantly iOS 14. Um, they keep changing tiny little minor things. We brought up the, you brought up the file picker earlier. They've changed how the file picker works in iOS 14. So we can, you can read this a few ways. Uh, cause I know you do this too. You do a check of which version. IOS is, and then you enable different feature paths based on that. Now me personally, I know. Mmm Hmm. But one feature disabled, one feature in those features has I tried to do two equal feature paths, you know, so I haven't done if you have iOS 14, ah, you know, I'm talking myself around in circles a little bit here because what I'm trying to say is. I do those branches just to keep up with the operating systems. I don't do it as features I'm charging extra for or anything like that, that, but at the same time, absolutely. Because, um, a lot of the more advanced features, like let's say metal, the rendering API on iOS, there are many versions of metal and metal support. I think there's four of them. At this point, different classes of metal devices. And you know, if you are running an iOS 12 device, you might not have metal at all. If you're running an iOS 13 device, you might have version one metal. If you're running a device released in the last year, you probably have a version two metal device, and those can definitely open and close feature sets. So it's tricky because those larger features. Boy, this is a long one. Sorry, there, there can be info P list ways to require them. It can be in the version number of the operating system, or it can be really at the API level where you ask the operating system. Is that feature there? James: [00:23:59] Yeah. I read this completely wrong and I'm so happy that you corrected me and yes, you're absolutely correct because, um, when iOS, so let's say you create an application for iOS. 12. Right. And that's like the first version. You're just like, I support iOS 12 and up. And you only use API APIs that are in iOS 12, right. Or older. You're totally good. Right? You never need to check a version number because you know that those APIs are available on, on your, on your oldest version of the operating system and the newest versions of the operating system. The issue occurs is yes, exactly. What Frank said is when a new API comes out and I want to use it, how do you become backwards compatible to ensure that my users using iOS 12, 13, and 14, all can use it. Or for example, yeah. An API changes and there's a new override. You want to take advantage of it. Like they did this for open URL. I think like the API changed at some level or something like that year. Frank: [00:25:03] Every year they change them all. Give me a break. James: [00:25:06] I think. Yeah. I think, I think, yeah, the, the bigger one was in like iOS nine or 10 or something like that. And we, we always have to handle it in essentials, but that what we do there is we do exactly what Frank says. We said. We do aversion check and you can do this in essentials or the core API that doesn't matter. And you say, Hey, am I running, you know, version 13 or above, then use this new API else. Either. Yeah. Disable that feature. If it's a new feature that you're enabling for that user or fall back to your old functionality. So sometimes you may have older code logic that's inside of your application to support that feature because you still want those users to use your app. Now, maybe. You later on get information that Hey 0.0, zero, zero. 1% of my users are using iOS 12. Okay. Now you can remove that check or leave it in. Who cares at that point? You know what I mean? So I did read that wrong. It's correct. And that's the same with hardware capabilities? I think the interesting part would be if you're building an application that requires. Hardware. How do you get around that? Like, can you, um, limit that and you were talking about info P list, which is, uh, on an iOS, on Android, the equivalent would be the there's using features and using hardware flags. So for example, you can say, my application requires a touch screen. Don't allow people to install it from the app store. If they don't have a touch screen, like you can do that, which is actually really cool. You can it for almost. A lot of features, not every feature, but a lot of features. You can do that for not necessarily for API as you can't be like, Oh, do you have a well on Android? I think you could say, you can say on Android, for example, only allow people that have a pedometer to install this application on iOS. You cannot, that's only on I iPhone five as maybe an above, right. And that's a little bit harder and trickier to do, which is, would be more of a. Frank: [00:27:10] Yeah, and it's always tough. So if you write an app that requires a pedometer. Even that one, I was confused. I thought there was an FOP list for that one, but whatever you write an app that requires that you put that in your description, you put it in your title and, you know, day one, there's a one star review. I downloaded this app and it doesn't work cause I don't have a pedometer. Correct. Ah, darn. And so that's more of an. Failing on the app store is what you, they should be covering those scenarios a bit better, but when Apple does it or Google doesn't cover it, the honorous is on us to do that. And it's tough. I was telling you the story. Um, when I first started working on ice circuit 3d, it was iOS 12. And I was like, Oh, maybe I'll support iOS 11 because, you know, I thought I'd support one year back the operating system. Well then 13 came now 14 and I'm like, I just enjoy increasing the minimum version of this app. I still haven't released over the years and I actually made a pretty big. Change going from iOS 12 to iOS 13, because there really was a performance difference between the iOS devices, between 12 and 13, the ones that were not allowed to upgrade to 13 kind of, cause they're kind of slow James, like, and my app was kind of slow on those devices. So it's interesting that sometimes you can use the operating system version number. To cover your bases on all that kind of hardware stuff, because hardware features become standard. Or if you have, um, the health app, you have pedometer, whether you have the hardware devices, they're not, I think it'll even use like, uh, the accelerometers or something to do it. So there's little tricks like that along the way. James: [00:29:01] Yeah, correct. I think also you can, there's a few little flags, even beyond that, the one I would say would be, um, architecture. So I remember using the arm 64 flag to say, I only want to support, cause this was a case where there was a year in which iOS supported both 64 bit and for many years and the 30 several for several years. Yeah. But then there was one year, which was like, Hey. Nope, like we're done with 32 bit. Right. Uh, and that was a flight. Do you know what what's great here is I, I, I know that I want to support these newer devices or this is a certain operating system and I'm going to use this as a limit, um, to get these certain devices where it was as a capability to say, Oh, okay, I want to support iOS 12, but I only want it on arm 64 bit devices. So that was another sort of, one of those quirky flags that I put in there. So. Yeah. Frank: [00:29:55] Yeah. You know, it's funny talking about that, that 32 bit to 64 bit, sorry, this is a total side tangent topic, but I was getting into the mano source code and I just noticed that a Mac used to be 32 bit and 64 bit. Well, the 32 bit Mac motto is gone. Well, we're done with that. It's like, not even in the, uh, the code repo anymore, you can't even build it like 64 bed only we've moved on. So I don't, I don't honestly mind architecture changes like that. It's so much easier, especially coming from a dotnet background to deal with platform changes like that than it is. Sam database migration. Those are a lot harder to deal with then, you know, a processor changing, but there is a second part to this question also that was, um, Uh, what do I need to learn to in order to release a free iOS app with limited features, but allow the user to buy into the full app. And that comes into James's absolute favorite subject, and that is in app purchases and receipt validation. I know you love it because you keep writing libraries that do it, and we've, we've done whole. Episodes on this, where we've talked about pricing models before, but I will say it is as simple as you're thinking it is you. I have a bullion flag somewhere in your code, maybe on the file system. And when someone doesn't in-app purchase. Through a series of call backs. You'll get a flag saying whether that and out purchase was successful or not. It's a little ugly, but you'll get through it and you'll save that somewhere. So if they succeeded, uh, write that to your database, write that to the file system and say, they've succeeded. If you're a little bit more paranoid, you can always do what they call receipt validation. To double check that they actually did pay for that feature, but all that's coming down to eventually there's a bullying somewhere in your code. And you have an if statement in your code to either show the UI, uh, that you might've been hiding before. That's generally the trick everyone uses, like all the code is there. You're just hiding the user interface for it. Okay. Uh, that's pretty much it in the olden olden days. Uh, we used to do pro and free versions of the apps, but I think that's a little bit past say, and people have come to begrudgingly. I'm one of them except in that purchases as the way of life. James: [00:32:28] Yep. That's pretty much nailed it. Yeah. I was going to say that you can do pro and non-pro, but I don't really think that that's a. Frank: [00:32:37] Is that? Yeah. How do you actually, how do you feel about that pro and non-pro versions, James: [00:32:42] you can do it and you can then try to upsell your users. But then the issue I have is you have to then make the decision. So here's the pro the pro is if you have a paid app, the only way the person can get that paid app is that if they pay for it, right. And like, you don't, you don't have to validate it. So great. There's no receipt validation or any, anything in there because. Guess what they paid for the app. Right? But you, you will probably still, by the way, have to put all of them, the bullying statements. Cause your code base is going to be the same with either the free or the non-free version. So you're gonna have these forking of, of it. So in versioning will be a little strange in IDs and automate all of it. It's not that hard. I just think that in the world today, it doesn't make a lot of sense to do it that way because. If you get rid of the free version or the, and at some point, just to have one version, how do you then migrate your paid users over to your free version to be the, you know, I mean, Yeah. I just think in general, it's either it's, it's paid. Like you're just, um, my app is paid, right. Because I'm period full stop. I'm a $20 app by my app. That's it. Right. And, um, or you have free version that you can then upgrade to the pro version if you will, or the plus version or do a subscription and go that way. And again, yeah, it's a, literally just a database now. Not just a, usually a flag. I use a, just a preference just in general. Um, And also the nice thing about that is that you can then of course, request from Apple and Google to say, Hey, um, let me also see if they did buy this. Right. Um, so let's say they do on install drop and reinstall drab. You would have a retrieve purchases type of thing. So it's all, all hope is not lost, or they could install that up on multiple devices too, and it's free. But then when they say retrieve, boom, the better way of doing it. Which would require servers and sign ups, which I don't recommend, but if you have assets and certificates, I don't, I mean, I only recommend this. If you, um, if you already have that infrastructure and you have a website and you want that to be all linked together and you want it to be seamless, that they can use it on iOS, Android, and windows, all under one fee is, is you basically have a user account that they log into. And when they log in wherever they buy, the thing, that is what would unlock it. So really your, your backend is going to do the validation and also say, Hey, this user Frank is a pro user of my app. So make sure that's unlocked on all the things, right. Um, that makes it easier than some users that are like, Oh, I got to buy your app or buy your in app purchase on multiple devices or whatever. That's kind of a pain in the, in the, in the butt. Frank: [00:35:35] Yeah, thanks for covering that. I totally neglected that on the cross platform, Flint I've really been pushing iOS on this episode on cross platform. Definitely have to kind of have to do user accounts because based on iOS, we have a little bit of iCloud actually, so you can save things there and they transmit between the different devices. It survives upgrades. Even if they install the app, it stays on iCloud. So benefits there, but yeah. Cross-platform you don't have that. So you got to build it yourself to do all that, which I guess it's like so many apps have user accounts these days. I barely bat an eye at it, but I still prefer the apps that don't have user accounts, I would say. So use that as a last resort. James: [00:36:20] Yeah. That that's what I would do is use it as a last resort and, and just depends on what your app is. You know, I. I always think it's a lot harder to. Go from paid to free within that purchase than to just start with free plus NF purchase, or just make the decision to say, this is how much my app costs and this is it. I still have not released the update for Island tracker that okay. That I it's done basically. But now where I need a test that on iOS 14 and the new versions of Android, like I, I'm just kinda scared to make changes. And Android has a bunch of requirements now and, um, the. You know, I had to go through a lot of series of changing the inept purchase structure, but my backend is ready. I've done all the things. I'm just tired. I mean, that's is honest. That's just me being honest, Frank, I am just Frank: [00:37:12] tired of fall. The sun is starting to set. Everyone's waiting for the second wave of the pandemic. But, um, I enjoyed this question because yeah, you say you're tired, but at the same time, IOS 14 has caused me to need to update all my apps. It's over it's thank goodness. It's not yeah. Like crashing bugs or anything. There have been iOS releases where all my apps were just crashing, but it's not one of those. Um, but it's little things, you know, like they're, they're always changing how search bars and navigation controllers work. And it seems to break every one of my apps on, is it me, James? Yeah. At some point you have to ask, is it me? Am I an idiot when it comes to search bars and navigation bars? Like they just don't. Blend together right in my head or something. I code them wrong. Cause every version of the OS I have to fix that code. And so this was a fun topic for me because I've been in update mode for the last, I don't know what the date is. Let's just call it two years. I've been updating my apps. James: [00:38:20] It's true. I mean, this is something that, you know, I ever developer needs to think about it sometimes. Cause it's easier to, it's easy to get your app out there, but. What about all those maintenance, maintenance, hardest part once your app is out, it's basically maintenance forever. Um, yeah. New features of it is that it's basically, you know, amazing. Frank: [00:38:41] I have a, I have a hot release. So, uh, the new update to continuous got accepted over the weekends. And I was excited over that. It was, um, going to be a three day update that took me three weeks. You know, one of those. Yeah. You're just like, I'm going to add these two features that people keep requesting an app store reviews. And somehow that turned into three weeks of coding, but I'm very proud of it, but yeah, maintenance programming takes up. I swear, I've written absent less than three weeks. Like I just can't believe how long this update took me. Yeah. James: [00:39:18] I did get a, a, I did get my I'm I'm reading. You're really isn't it. I did get an, a, a test flight notification. I was like, Ooh, something's happening. But yeah, you, you now support for iOS 14 key support, which is cool. Frank: [00:39:32] It actually, is it turns out, um, you know, you, you imagine who's using your apps and then someone slaps into your face, slats you in your face and says we're using your ass. It turns out obviously a lot of students are using my app and, you know, uh, you know, what they teach students console, right line and console read line. And those are important. James: [00:39:51] I'm, I'm writing some new modules for working with the team on, on Microsoft learn and it's like introduction to.net stuff. And . Uh, you know, we do Frank: [00:40:03] tell me console right line and console line. James: [00:40:05] That is correct. Yes. And what, and what the difference is between counsel read line? And right line and debugged outright liner. So, um, yeah, it's very, there's a trace line too, which is also fascinating Frank: [00:40:18] and they're configurable. You can override them crazy. James: [00:40:22] I'm not getting into that depth cause that's too much. Yeah. You have a new font. C-sharp nine support. That's cool. I ask it on a core preview as a fancy update. I mean, he busted on my iPad. Frank: [00:40:31] Yeah. The three day I went a little obsessive with it, but that's cool. It's cool. I like making my apps powerful. You got lots of fonts now. I don't, I didn't mean to turn this into a commercial. I just wanted to say, James: [00:40:43] how do you we'll support iOS nine or later? Those that didn't make any sense. That's five years of devices. Frank: [00:40:50] It can't be true. Which, which app are you talking about? James: [00:40:52] Continuous is what it says. Frank: [00:40:54] That can't be right. James: [00:40:56] You haven't sent for iOS nine or later. I think you put 64 bits of core for sure. But yeah, we support the iPhone five S sir, Frank: [00:41:04] I was going through some ice circuit code and, um, there were, uh, F iOS it's three checks and I was like, okay. Ooh, I think I can finally release the, or delete those lines. The check for iOS three. Wow. I've been doing this for a lot of years. James: [00:41:22] Indeed. Well, if you have feedback for the show or you have a topic that you'd like to have us discuss in more detail too, sometimes we talk about stuff like, you know, Gary, Sandy, he's like a Britisher. You've talked about this, but you know, sometimes related to go deeper on a topic, it's always fun for us. I've got a merge conflict that FM, and you can hit that contact button. Like I said earlier on the show, um, you know, check out all of Frank's apps. Cause why not? Yeah. I mean, Frank needs to be supported during these times, uh, but that's going to do it for this week's episode or merge conflicts. So until next time, I'm James Monson Magnum Frank: [00:41:53] I'm Frank Krueger. Thanks for listening.