mergeconflcit305 === [00:00:00] James: Welcome back everyone to merge conflict. Your weekly development show. I'm James Montemagno with me is always Frank Kruger. How's it going, buddy? [00:00:16] Frank: Oh, hello. Hello. Uh, first time caller. I'm happy to be on the show. I've heard a lot about you, James, and this podcast you do. I'm excited to be. Oh, Frank, [00:00:25] James: this is our [00:00:26] Frank: podcast. Oh, oh, oh, we're doing that one. Hi. Hi, I'm Frank Krueger. Welcome to merge conflict. Thanks for tuning [00:00:32] James: in. And if you are a recent listener that heard Frank on another podcast, Frank is femininely more famous than me. Congratulate. [00:00:41] Frank: Oh, thanks, James. No, I'm not more famous than you, your YouTube famous that that's just, you know, that crosses barriers. Um, but thanks. I was on the change log it's it's a, it's a classic podcast it's been around forever and it was fun. I don't know if you listened to it, but they're a really good interviewers slash we talked about a topic, but, um, they're really good at having a discussion, really good house. That's what I'm trying. [00:01:07] James: Absolutely. I haven't made it all the way through yet. I'm about halfway through because I have it bookmarked on my other computer where I started it. Cause I, I should just subscribe and just download the one specifically. But that being said, uh, you know, I tweeted about it cause like, even in the first 10 to 15 minutes, I learned something brand new about you and we've done your story and we've done a bunch of, and I've been your friend for a decade, Frank. I learned so much new from, from you in general, on this podcast, it's an absolutely delightful listen, and I will put it in the show notes so everyone can listen to it. And yes, there are spectacular interviewers. I wish I was that good of interviewers on the. [00:01:46] Frank: Yeah, they, they, they have a great demeanor, in fact, it was one of those recordings of a podcast where we spent the first hour talking about eighties and nineties horror movies, and then eventually realized, oh, we're supposed to be doing a tech podcast and then dove into, it says it was a lot of fun. Um, it's interesting. I'm trying to guess it what you could possibly not know about me. And like, we, we did like a whole two-hour episode on me and that's, that's basically my whole life. Um, I can't even guess which one are we talking about? [00:02:15] James: I don't know. I'll have to go back and listen to it again, [00:02:18] Frank: so, okay. You're making it up. You're making it up. [00:02:21] James: As I was listening, I was like, whoa, this is really, I mean, it was a great podcast. So if you're coming from that podcast, I'm James that's Frank and we do it. Software development podcasts. We often talk about mobile development. Usually with Donna, not is sometimes you get into the swift and the Collin worlds. We talk about what's new with apple and Google and Microsoft. We're both mobile developers. We're both desktop developers and we're kind of sometimes. Terrible web developers too. Uh, and that's what we do here. We talk about that and we've got about 300 plus episodes of enjoyment, if you can binge. So, you know, cause like apple TV, you know, plus they only have, there's a new episode every week. But with this podcast you can, there is that, but also a 300 episode backlog. And then you can just binge through those. [00:03:06] Frank: Do you think you'll ever go back and listen to all 300? Well, I. I would say upwards of 200 of them. [00:03:14] James: No, never, [00:03:15] Frank: never. Nah, come on. Okay. Well we'll put them in the vault and yeah. Thank you everyone tuning in from change log, actually. I'm sorry. We're just gloating about Frank today. Um, my, my Twitter account crossed 10 K because of that podcast. So thank you podcasts for getting me over that stupid mental hurdle. I don't, why do we care about numbers? It doesn't matter, but it matters because now I have a K and I like case. Ooh. [00:03:39] James: Yes. Very very nice. Yes. A vanity metrics, right? [00:03:46] Frank: Yeah. I shouldn't admit to it, but you know, it's nice. It's nice. I'm honestly surprised that many people care what I have to say half the time. I'm just making dumb jokes. [00:03:55] James: I believe that that is everything that I do on the internet. I don't know why anybody follows me or why anyone listens to podcasts except for that. We're awesome. And you should always subscribe. Okay. Frank, let's get into a topic this week because. I don't know what's right. And I don't know what's wrong and it is iOS specific. Okay. This is an iOS conundrum. [00:04:21] Frank: It could be anything, James, you know, it's a big operating system these days. Remember iOS two when we actually knew how everything works [00:04:28] James: well. Well, Frank, what is the one thing that I have talked about the most on this podcast for either. In-app purchases. There we go. We're back, baby. We are back in [00:04:40] Frank: after for real. I was doubting it. I was doubting it, but how, I guess we took a few months off. They didn't mind [00:04:47] James: if it's, if it's not machine learning and robots and AI, it is in app purchases. Uh, conundrum Frank Krueger and I I've had, so for historical reference, if you're just now listening to merge conflict for the first time, Frank and I indulge, we dabble. If you will, into the creation of open source libraries that developers can use and it against our greater judgment, uh, we do these, we put them out in the world and then we use them ourselves, but we also have to maintain them. And. Modify API APIs and take poll requests and do things which is a joy. It's one of my favorite parts about being a developer in this day and age of collaborating with the community. But here's the thing is often when I create a library, I create the library for myself. And this is the first mistake because I'm like, this is the API that I would like, and this is how I would use it. And this I don't care about your features. Ha this is for me. Uh, do you ever feel that way when you create a library? [00:05:45] Frank: Ah, I wish I felt that way more, you know? Okay. Uh, yes. Yes, of course. All your library stirrup for yourself. Of course. Um, I, I'm not good at anticipating where everyone else is going to need, but I feel like that also has held me back from releasing a lot of libraries. So much formality around libraries and everything. It feels like you really want like a good idea. Tightly implemented with a good API. That's what a library should be. There's parts of me that just want libraries to be junk yards. Like I was writing a table view controller the other day. James, how many table view controllers have you written in your life? I know you're you're on Maui Xamarin forms. Come on. How many of [00:06:31] James: you don't a lot, a lot of UI table fees, many, many, 800 a thousand billion. [00:06:37] Frank: I was writing out another one and I'm like, I swear, I've written this code before, but the problem is that code is kind of buried into an app and everything. And I don't really see it and I don't release it because I don't think it's a unified thing idea. I don't know about like managing support for it and everything. And so I feel a little bit bad that I never, uh, actually share my own code enough. And it's, I I'm bringing it up only because it's something I want to work on. Be aware everyone. I'm about to just start releasing a bunch of libraries with no theme to them other than here's a Hunka code that I want to be able to use. [00:07:12] James: Yeah. It's, it's, it's, it's tricky. It's a tricky battle. And when I first came about. Um, doing billing in my, in my applications, like in app purchases, I struggled a lot in John Dick on the Donna Maui team. He supplied me some code. He kind of did what you did. He's like, here's a chunk of code, have fun. And I was like, this is amazing because I didn't know much about iOS and there's delegates and there's this whole call back. It's very complex. Android at the time was very complex and it's gotten a lot better. Now they have a new library that is much more elegant. The, the problem that I had at the time at least was I was only doing non-consumables. So one time purchases, and we've talked about how I've gone all in on subscriptions, which is going interesting. And we'll give an update in the far future about that. Uh, we also have to handle consumables, which are things like coins that people consume. And then you have to deal with the complexities of the different API APIs and they evolve over time. Uh, apple recently added tons of new APIs for subscriptions. And, uh, we talked about the different offers that you can have and, and things like that. And then Google also introduced, uh, another feature in their application model, which was, um, that you could bond. You could buy in that purchases in stores or like, you know, if you're in India, there's like different per purchasing processes. So the concept was that if someone could buy it and register it through like a coupon and then you had to acknowledge it. So it's very a strange process. And now every windows, iOS and Android all worked very differently. So, um, but like, [00:08:59] Frank: Okay. Can we dive into that? Just for a moment? It sounds like that's not the main part of your story here, but I'm, I'm, I'm curious is the expectation then that, um, so someone redeemed this code when they open the app, the next time you're supposed to pop something up. Is that coming in? [00:09:14] James: Yeah, the recommendation is that when you start the, when you start your application, you query to see if there are any purchases that haven't been acknowledged and then you acknowledge [00:09:25] Frank: them. Fascinating. So there's actually a flag there somewhere or a part of a query. Okay. Okay. There. [00:09:31] James: Exactly. And yeah. And, and the other issue there too, is that you have, um, You, you also, then you could think of it as, um, maybe the, the purchase is pending. So it is a purchase. You get that back and, and, you know, you have to acknowledge it eventually, but you don't acknowledge it until it's purchased. So you're at, might be in the state where, oh, it, it is pending purchase. Maybe it's just waiting for their credit card to finalize. So you got to figure out what to do, kind of it's it's in a weird state. What I do in my apps is I just, you know, as soon as they buy it, I acknowledge it. I'm like, oh, did they purchase it? They acknowledged it. They're good to go. Uh, and you can always restore, right? There's always a restore basically that enables you to go through and then, oh, I restored. And then here are my purchases. And then here at my transactions. [00:10:26] Frank: Okay. Okay. So it doesn't sound too bad to me. You kind of had me freaked out a little bit there where they actually do. They actually create a line item on Android, even though the credit card purchase hasn't gone through. That's scary. I don't want to have to manage all that stuff. I'm also thinking where the heck is the operating system. Why isn't the operating system doing all this for us? Like. I still want to go back to what is the expectation? So as an app, what are you what's, let's talk at the UI level. What are you supposed to do at the UI level for the signal? [00:11:00] James: Nothing really. Okay. Am I understanding you just do it? It's all [00:11:03] Frank: programmatic then you're saying. [00:11:06] James: Yeah. And the problem here too is on Android specifically, is if you do not acknowledge a purchase within three days, they will refund the transaction. [00:11:19] Frank: Okay. Okay. This is all blowing my mind a little bit, because so you re re redeem one of these in-app purchase things. I guess what they're saying is they're not going to just pop the app open immediately there, or will they pop your app open immediately or are they just saying, okay, you did your redemption, but it's up to you to open the app within the next three days so that the app can acknowledge it. Is that when you're. I guess it's all freaking me out, man. Well, [00:11:48] James: these are called pending transactions and I still don't understand how they, how they work. But you have a library, James. Yeah. I have read the documentation, but from my, from what I've seen, I do not know how to do that thing that I just told you. Like, I do not know how. Buy a thing in the store somewhere, you know what I mean? And do that thing. So it's very hard to, to do it, but you have to, this is a, not an opt in. It is a forced thing that you have to do this thing, uh, in your, in your library or else things will go away. That's why they force this acknowledgement flag on you. Uh, so I don't actually know a hundred percent. All I know is that. That if someone was doing this, I'm assuming it opens the application because it's aware of it. And then you would acknowledge it. Or in my instance, reunion restore your, your, um, purchases for all intents and purposes. Um, there, because it it'll show up, it shows up that it was purchased and just not acknowledged. Uh, but it's, it's a very weird process. But if we think about this on iOS, there's something similar, which is finished transaction, you know, about finished transit. [00:13:01] Frank: Yeah, I suppose I do. I've had to implement this once before and I'm digging through my memory. Um, I thought this was just a part of the standard set of callbacks, though. It happens pretty quickly when you make your purchase. Is this something else that can happen? Async when your app is shutdown? [00:13:19] James: Well, so finished transaction is. An interesting one because okay. Finished transaction. You're supposed to call only after the app has finished all work. It performs to complete the transaction. That's what it says. Okay. [00:13:34] Frank: So there's documentation. [00:13:37] James: Cause there is technically like this, this queue or whatever it says, the transaction state determines which step you might take. If it's failed, you might update your user interface. If it's successful, perform all necessary actions to unlock the functionality the user has. Um, for example, downloading content and then finish the transaction. [00:13:57] Frank: Uh, um, and, and to be clear that this happens after you call the purchasing API, as in the user wants to buy one of these things. These are the callbacks for that API, correct? Is that correct? [00:14:07] James: Correct. Yeah. So in my mind, in my mind, at least what I've. Assumed, uh, was, well, I should always just finish every transaction in my library. Right? Like you make a purchase if it's successful. [00:14:27] Frank: I mean, yes. I, I can't see. Yeah, I can, I can see you sitting down four years ago or whatever, and decided back. Of course, I want to finish it. Why? I mean, I'm sure I have that exact line of code in there. Finished transaction immediately. [00:14:42] James: Finish it immediately. Now, here is the conundrum of the day is, is this it's very specific to this, which is on. Okay. The okay. Let's let's go back to how Android works. Okay. You're [00:14:58] Frank: you're messing with me. iOS, Android. Okay. Yep. I'm [00:15:01] James: ready. Android. There's consumables. Non-consumables subscriptions now subscriptions. And non-consumables AK one-time purchases work the same. You have to call acknowledge. Okay. Acknowledged. Yes. I acknowledge you now, consumables are different. Okay. Okay. If you have a consumable, you have to consume it via an API, which is consume, which also acknowledges it at the same time. So there's multiple steps that you have to do for consumables, but you have to. E up that consumable. Okay. You can [00:15:48] Frank: just tell all this was in like the worst PM design meeting ever. They're like, I can almost see them thinking like, okay, these consumables, maybe they're like coins. Maybe they bought the coin, but they haven't spent the coin in the game. And that's why we need the consume thing. Exactly. And you just like developers should have been screaming. No. Purchase system. Just give us a simple purchasing system. Yes, please continue. [00:16:15] James: It makes it, it makes it so much more complicated because what you really want. Let me buy an item and let me determine if I can buy this item more than once. That's the only diff [00:16:25] Frank: yeah. Hey, guess what? We we've done sales on the internet for awhile. We know how they work. There's an inventory system, a shopping cart and acknowledgement system. Tons of those, but no, we have to consume the consumables and acknowledge the subscriptions. Got [00:16:41] James: it. Okay. So here's the conundrum is while on Android. Two different API APIs because there's two different things on iOS. Nope. There's one API finished transaction. Do you know what finished transaction does it consumes a consumable. [00:17:02] Frank: Lovely. I don't know. It's sounding like they operate similarly to each other. Um, so you would have, uh, I don't recall your API. I apologize, James. Um, but do you, yeah, there's just purchase, that's it. [00:17:20] James: Period. There's there's per. Okay. So for, for that there's there's purchase consume, acknowledge. Those are the current AP. [00:17:30] Frank: Yeah. I'm your library? My library. Yeah. Okay. So you separate, consume and acknowledge. I thought that the two other libraries joined those [00:17:40] James: two concepts, not Android. Android has literally an, an API called consume and an API call. They acknowledge. [00:17:48] Frank: Ah, this is why you shouldn't adopted their words because now it's just, I think that you're just getting caught up in the names, um, rename those functions, C and D and see how far you can get. We're just renaming them C and D. [00:18:05] James: So the main problem here is that also when you restore transaction, The apple recommends that you finished transactions that aren't there. So I I've been doing that. So on, on iOS, I just been doing all these things automatically and I'm like, this is fine because that's, I don't use consumables, basically. That is why. So some issues came up recently, which was, Hey, I have consumables and I don't want you to auto finish my consumables. And the problem is, is because once you consume a consumable, you don't get it back. [00:18:37] Frank: Notification, no history, [00:18:39] James: no history. Once you consume it, it's gone forever from both ETF. [00:18:44] Frank: Yeah, boy, boy, James, I'm getting it now. It should be a two-step process. I'm getting it, but it's going to break your APM, API and everything and break other people. Uh, did that person happen to describe what they're doing? The consumables for? I'm just curious. [00:19:00] James: I believe it was a game similar to your coins. Yeah. [00:19:03] Frank: It's the games. Okay. Yeah. [00:19:05] James: So [00:19:06] Frank: yeah. I mean non-consumable is your, yeah. Okay. So right now, if I want to do of subscription in your API, all I have to do is say purchase, that's it. And then that's a full stop [00:19:25] James: on Android. You would acknowledge it [00:19:28] Frank: on iOS. What happens if I acknowledge it? [00:19:31] James: Nothing. It just returns. Excellent. [00:19:34] Frank: Yes. So you should. Okay. Just for, just for good order purchase, acknowledge for a non-consumable same thing, purchase acknowledge. Yep. And then the big complaint is when you purchase a consumable, now you are actually consuming it in your [00:19:54] James: library, correct. iOS automatically consumes it. Android. You are forced to consume it on. [00:20:04] Frank: Hmm. It sounded like though that your acknowledged on iOS could consume it then. [00:20:09] James: Uh, so Frank pop up a bump here is where the conundrum goes. Oh no. Is I have introduced a brand new pull request into the system that does not auto finish transactions on iOS. It puts, it gets rid of acknowledge. It gets rid of. All of this. I used to have like a finished transaction, so you could finish one annually. It gets rid of interest, all of those. So it breaks the API completely. I'm all about breaking this API a hundred percent. Okay. And what I'm doing. Cause the first thing I did, I did a really super overly engineered. Which was, I was like, Hey, for, for some specific methods, like purchase and restore. And like these things pass me a list of strings. And then I won't finish. I completely over-engineered it. I was like, if, if you pass me like coin 100 coins as a string for your thing, and I won't finish that and I won't do this thing, it was like way over engineered. I'm passing. So raise of strings. So here, terrible idea. In my mind, I was like, this is gold. You know what I mean, [00:21:16] Frank: James, I'm not getting your array of strings. Can you, can you explain that again? 'cause [00:21:20] James: imagine. Cause here's the thing on iOS. I have no way of knowing if an item was a consumable or not. It's impossible for me to know it's not [00:21:31] Frank: recorded. [00:21:32] James: If you tell me. What IDs are consumables, and I can do the right thing, which is not auto consuming. [00:21:43] Frank: Yup. Um, I'm going to say you made the right decision by not doing that because. I was thinking that at first you can either be clever or just tell everyone, Hey, sorry, there's a new second step. You have to do the second step. And although it's painful, I'm totally agreeing with you. I don't like the fact that it's, it's making the API uglier and weirder to use and a little more mysterious by trying to be clever because the obstructions to leaky or whatever you want to say, wasn't clever enough. So I'm hoping, uh, yeah. T two, two methods. Both. Async probably it's easy, man. [00:22:23] James: So the, the fascinating part is, so the person that did the report did a PR and you, it was like, oh, I see what you're doing here, but it actually leads to other problems. And it seems like it's a it's, you know, problematic long-term. And I was like, I do agree. I do see it. Yeah. And I, and I haven't released that API. So on preview and just beta packages, I'm free to break things as well. He did a pull request. And what he did is he did a static Boolean that says, you know, auto finalized. No, no. And, uh, I thought about that originally, too. Uh, that was my first thing. I was like, let me just put it in a global bullying. That seems like a great idea. And then I don't worry anyone and no one's going to know that bullying. [00:23:05] Frank: Yes, correct. Discoverability is terrible. And literally no, no global on-off switches because things just don't work. Well. I, I feel like there is a bad trend in programming right now. We're making everything global variables and it's just not cool things stomp all over each other. It works fine for one user, and then you try to add a second user and everything breaks. So I disagree with that one. There's a terrible one. Um, in San Fran, have you ever had to play with the one that turns off a UI thread detection in sand? [00:23:39] James: Yeah. Yeah. [00:23:40] Frank: That is the scariest global variable because it's not thread safe in any possible way. And so you're, you're always running into race conditions. Anytime you try to decide. It's fine. Cause it's just a debug feature, but it's still a little bit maddening when you run into race conditions with it anyway. No big, no to mutable global state. [00:24:00] James: Yeah. So I, I went back and I said, you know what, if it, if it it's, it's, it's either always on or it's either always off, you know? I mean, and it's not used. I, I am like, it needs to not be a user choice. I think that's my new thing. To align. The API is closer between Google and apple. I decided I'm breaking all the API APIs. I'm just breaking all the names and because they need different variables pass in and I created a single new method. So you would purchase, async get back that information. And then there's a new method that replaces all the other ones besides consume, which is finalize and acknowledge. [00:24:51] Frank: Okay. I would've just called it finalized purchase, I think, but, okay. [00:24:56] James: Yeah. [00:24:57] Frank: Um, it's definitely explicit. I think we should workshop the name a little bit, but I get I'm. I'm happy you introduced it. I'm agreeing. Um, yeah. So now. A method B method, both methods are required. I'm assuming no matter which one are you doing with the only caveat that if you're doing a consumable, only call be when it's time to consume, is that right? [00:25:20] James: That is correct. Yes. And if you call consume purchase on iOS, it also now calls finalize and acknowledge racing. So boom. It does it. [00:25:30] Frank: Oh, you still have a actual consume method in your API. I do. [00:25:35] James: Yeah, [00:25:35] Frank: gross that shit. Two methods. That's all you need. [00:25:38] James: Here's the problem is on Android. It's literally to eight different API APIs in their stuff. So I wouldn't know what to do. [00:25:48] Frank: I thought you said that there consume also acknowledged, but I guess that's [00:25:52] James: not true only for a consumable. Not for the other thing it says. Yeah, [00:25:57] Frank: but that's fine for consumable though. You can, with their own [00:26:00] James: exemption. And I wouldn't know if it's a consumable or not, because there's no way of. This is the conundrum Frank Kroger. I don't like [00:26:07] Frank: the conundrum because it seems so obvious. And yet you keep saying it doesn't work. It doesn't work. Hey, [00:26:14] James: there's two different APIs. [00:26:16] Frank: So let me get it straight one more time. So this is intro to beginner's tutorial for James's library. I know I purchase, I think great for all three. It doesn't matter which one? Correct? Now subscription, whatever immediately I, I call your finalized purchase async, which is what it should be called, uh, for non-consumable I finalized purchase say sync. Great. When it comes time to consume it, I guess I can query your thing. Find out that there's a pending thing out there, pending purchase out there and then consume it at my own or the user's leisure by calling also finalized purchases. Correct? [00:26:59] James: Yeah. Okay. [00:27:00] Frank: That's correct. It's fine. [00:27:03] James: It's fine. What's wrong with that [00:27:05] Frank: is fine. Yeah. What was it before? It just did it, did it, did the step automatically in all three conditions? I guess that was a little greedy. It's a little green greedy. It was really just the coins. Right. What else could you possibly use consumables for? I I've, I'm trying to think of other apps. I use consumables for. I think you are arguing for my mesh conversion app. Remember you wanted people to buy into file sizes. Do you remember that argument for in-app purchases? [00:27:39] James: Yes, I do remember that. [00:27:41] Frank: I think that was one of your crazier in-app purchase ideas. Don't think I'll implement that one. I will go for your subscriptions and, um, consumables, consumables seem too [00:27:51] James: weird. Yeah. What I could do. Okay. So here's what I could do is I could get rid of. Consume. Okay. We could get rid of this. And if just yet balling, if we did that, I could pass in an item type. You could tell me what type of item it is. I don't like that either, because then I would be able to call the right method. [00:28:14] Frank: Yeah. Isn't that strange that they don't give you that? [00:28:19] James: No, it is strange. And then windows is also different because the, you also have to call consume on a consumable, but you'd need different information for that one. So it's, it's [00:28:29] Frank: tricky. Windows tells you that it's actually a consumable in that case. [00:28:32] James: A Dez. Yeah. That's nice. Yeah. And then funny enough on windows, there is no, there is no, there is no acknowledged. It just does it automatically. It's like you purchase. You know, I mean, [00:28:45] Frank: honestly, purchase a sink. I get why you threw it all in there because it kind of should be just one [00:28:53] James: thing. Yeah. And funnily enough, when, when Google introduced, I had already released the library, then Google introduced acknowledge async right. So I had to like shoe horn this in and I had to make the decision at that time was, do I auto acknowledge everything. And that seemed problematic due to their craziness that they had to do. Um, and that just didn't feel correct. So I diverted the API. So this actually brings the API APIs together again, but I, it does break every single app out there. [00:29:29] Frank: Oh boy. Yeah. That's tough. Huh? [00:29:32] James: Tapping. [00:29:34] Frank: I, I think you just have to explain your. [00:29:37] James: I do have a Remi dot text that pops up when you install the library [00:29:41] Frank: noxious, like that [00:29:43] James: is a very ball, big breaking change. You must call this blah, blah, blah. [00:29:49] Frank: Yeah. I mean, they'll find out very quickly during testing. Um, yeah. How, how are your download stats? Do people continuously update your library or is it more like on the big releases you get a lot of downloads, [00:30:02] James: big releases that's for sure. I'm. I mean, the, my last actual stable release was a year and some odd days ago. And yeah, you know, the, most of the newer ones, they get, you know, hundreds of downloads, maybe a, a few thousand downloads compared to the stables, like 60,000. But it's a, it's a hard one, right? This is a, this is a, this is my hardest library because it deals with money. We've talked about it before, like most libraries. I don't necessarily deal with money. You like, you might sell your app that use the library for money, but like, this is literally money for your app. [00:30:49] Frank: Yeah. And I don't know, uh, I don't think you you're, you're not gonna break anything true. What's going to happen. So they'll think the worst case. So someone updates the library, they don't call your second function. It would be like, um, The state would never change on the item. Right? So hopefully people's UIs are displaying the state. I'm just trying to think of like, will it be obvious if someone updates your library without knowing about this change and I'm guessing it's going to be pretty darn obvious, pretty darn fast. So I think you're going to get away with it. [00:31:30] James: Yeah. The, the real question is what happens if I don't call finish on a transaction? [00:31:41] Frank: It's sounds like that transaction is going to have a weird state. You allow people to read the state of the transaction, right? It probably just won't have a completed state. It'll have a pending state. You should probably figure that a little bit. [00:31:55] James: Yeah, it should. Yeah. [00:32:00] Frank: I, I think this is going to work fine. It is a conundrum, but I think you've rubber ducked it very well. We've talked to through the only big pending question to me is whether to actually have that consume additional method or not. Yeah. Yeah. Um, it's going to work. Chains have faith. People will, people will go with you. Yeah. [00:32:24] James: Yeah. I mean, according to apple, I'm reading, I'm reading things. It says every transaction, regardless if it's succeeded or failed needs to be finished and. Basically it says that like, I believe on iOS, you will still get paid. It says completed transaction, provide a receipt and transaction identifier that your app can use to save a permanent record of the process to payment. [00:32:50] Frank: So you're saying the payment would go through anyway. [00:32:53] James: Well, they've already paid for it. Okay, thank God. I [00:32:56] Frank: don't know. Uh, you're freaking me out a little bit because I remember the last time I used your library as, as, as like James, I'm going to use your library and you're like, you know, you should just copy and paste the source code into it. Yeah. And I was like, why James? Why? He's like, yeah, maybe I want to change something here or there. And so I'm using a hacked version of your library and now, and now I'm just, I think I want to throw that away now. And. Wait for you to do this update because this update sounds pretty good. [00:33:26] James: I think it's pretty solid. Um, I think it's good. We will see, um, I think it'll be good. People will test it. It will happen. I will read more documentation, but you know, I think this was the battle of do I, do I create a, a Frankenstein ugly, ridiculous API. Do I do global statics or do I do, do I have the courage, Frank? To break everything and rethink about all the mistakes that I've made in the past. [00:33:58] Frank: You could change the name of the purchase function, and that would guarantee that it would break everyone's code and they would have to take a second look at it. Just [00:34:07] James: saying that's very true. Yeah. [00:34:11] Frank: It's tough. It's tough. Um, Yeah, it is breaking people. And my general rule is you never break people, but this is, this is kind of important stuff. As you said, it's money. It's important stuff to get it right. And you just put the caveat and poor in your read me. [00:34:28] James: Well, if any of y'all have feedback on if what I should be doing or for, you know, more, and you're like, wow, y'all spent 30 minutes. And James was absolutely incorrect about everything that he said, please let me know right into the past. [00:34:45] Frank: Way better than a global bullying promise [00:34:48] James: it's going to happen. All right. Well, let us know what you think of this. Or if you've run into, you know, situations yourself where you're like, this is the right call, this is, and this is how I deal with this. This is how I relay the information to the people using my library, let us know good emergent conflict out of them. There is a contact button. You can also hit us up on Twitter at merge conflict, FM or James Bonta magnet, or proclaim them on Twitter as well. That's all at conflict to have em go there, but. Frank famous, Frank, [00:35:16] Frank: that's [00:35:17] James: you? I do think that that is going to do it for this week's podcast. So until next time, I'm James Bonta mag now, [00:35:25] Frank: and I am Frank Krueger. Thanks for listening. Nice.