React Native In-App Purchases (iOS) - incl Backend and Sandbox testers from scratch

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today i want to talk about in-app purchases for ios using react native and the reason i'm making this video is because i've recently made an app a gr365 academy trainer which is released in on friday which has in-app purchases in it um and that was an absolute pain in the ass um it was an absolute nightmare to make because um as somebody was completely new i didn't find the documentation to be all that clear and i was just going through you know little snippets from stack overflow and so on and uh it was just a nightmare so i wanted to make an actual comprehensive video which uh we'll go through how i did it because i've seen some videos which were really good but then they might say something like oh so now you just want to send this data off to your back end and have that process to do a receipt validation for you and when you hear that as somebody who is doing their first ever in-app purchase i don't know about you but that just confused me because i had no idea what i was i didn't even know i needed a back end so i will also talk through setting that up and it's not anywhere near as confusing as it first appears so if any of you watching are an expo refugee like me meaning you've been forced to you were making an app with expo react native and you were forced to eject to the bay react native workflow just to add in app purchases then you may have come across the problem of so in order to actually make the ios app you need to be on the mac now i don't have a mac i do have a mac virtual machine which i had to get running uh just because of this restriction um there are other options like uh you can you can actually rent a mac cloud service i used one of them for a while called marking cloud and that was really good there are a few other things you might want to check out um but yeah you will need access to a mac unfortunately okay so the first thing we're going to do is do npx react native init and i'm just going to call it rniap so we need an actual react native project obviously okay so once the project has actually finished being created we're going to open up xcode and we're going to go to file open [Music] okay and within the project folder we're going to go to ios and then open up the workspace and as that's happening you can see one of the limitations of using this in a virtual machine is is this it actually runs pretty fast but the graphics only has 256 megabytes of vram so everything is actually processing fast but it's updating to the screen so slow that we get these uh you know little artifacts when we move it once xcode is loaded um just click on your project there and you will see over here we have an identity section now it's very important to get rid of this dreadful bundle identifier and add your own so you're going to want it to be an inverse url format so i'm just going to do com. my name and then dot rn iap okay um because that is how it's going to be identified when you actually upload it to the app store and through app store connect then we're going to click on sign in capabilities and check automatically manage signing and then find your account you're actually going to want to go into the xcode preferences if you haven't already and sign in with your apple developer account now unfortunately you need a paid apple developer account to do this otherwise you won't even be able to get access to the app store connected to tour which is a real shame because it's very expensive like 99 a year is quite a lot of money but there is no way around it unfortunately you do have to have a paid developer account so once you've done that you've selected your team you've got to automatically manage sign in we're gonna go to add capability and scroll down until you see the in-app purchase capability and just double-click that to add it and it's gonna do some processing here setting you up the certificates and and so on okay so once you've done that um we can actually head over to app store connect and actually work on creating the in-app purchase so here we are at app store connect now there is quite a major prerequisite here which is that you're going to want to complete everything in the agreements tax and banking section which is where obviously you have to agree to all the um different terms and set up your tax and bank information because otherwise apple you know they're obviously not going to know where to pay the money um so you'll have to go through that which is a bit of a tedious process but of course it has to be done um and also take note of this users and access section because we're going to be revisiting this later in order to set up test users to test in-app purchases so let's go to my apps and click the plus icon new app and i'm going to select ios but name it whatever you want your app to be called i'm just going to call it rn aap test a primary language i'm going to choose english uk now click bundle id and this is where you're gonna have to select the bundle id that we just set up in xcode or which hopefully set up for you automatically uh i have two here are an iep test and rniap this is just one i was messing about with earlier i'm gonna select this one which i just created right now now if you can't see that there don't panic because this is a issue that i encountered myself when i was making my previous app you're going to want to go to your developer.apple.com and sign in and when you're here click the certificates ids and profiles now click identifiers and click the little plus and here you're going to want to register a new app id it's going to be obviously an app and then you're going to want to set the bundle id and set it to well the same bundle id that we were trying to do in xcode um so just set that up there and then give yourself a description and obviously make sure that in-app purchases is uh selected and then you're gonna have to just run through the rest of the process to create it and then it should be there so you should now be able to select your bundle id now the sku as it says here is a unique id for your app that is not visible on the app store so it's basically just like an internal unique id so you can just make that whatever you want i'm just going to call it rniap tutorial now this user access is to do with is not to do with actual when it's on the app store and your customers it's actually to do with people on your other developers on your app store connect account so uh pretty much we can leave it at full access um if you do have other people using your app store connect account uh obviously i mean you'll know the limited access and how to set that up but we're just going to leave it at full now click create and this will create a brand new app listing for us so this is the page where we put all the information about our app we put our screenshots our text a description privacy policy all that is also where we upload all our builds of our app so what we're going to do is uh go down to the in-app purchases on the side and click manage while we're here we're going to click add and there are four different types of in-app purchases we can make the only one i'm going to cover here is an auto-renewable subscription but we also have consumable which are things that are only used once non-consumable which are things that you actually purchase in the app and you have access to indefinitely and then obviously you're also renewable subscriptions like your netflix your amazon prime and so on uh and then you have a non-renewing subscription which is just like an auto renewable subscription but it doesn't really obviously so i'm gonna go for auto renewable subscription here i'm gonna click that click create so it asks us to enter a reference name and if we click the little question mark we can see that it will be used on app store connect in sales but it won't be displayed on the app store so it's essentially for you how you're going to reference it so i'm just gonna call it uh premium access now product id this is important because this is the idea that you're gonna use within your react native code to access the purchase various different you know style and format rules that you can use for the name like uh revenue cat recommends that you use like the initials of your app and an underscore then the price then an underscore then the duration but i mean really it can be whatever you want as long as you remember it that is completely fine so i'm gonna call mine rt underscore 699 underscore 1m i'm following the revenue cat style guide so rt or rniap test 699 because i'm planning to price it at 69.99 and 1m for one month i'm gonna click next um now it's gonna ask us to create a subscription group so essentially you can have groups of subscriptions users can subscribe to one within the subscription so say you have a premium access you might have a monthly plan and an annual plan and they can only subscribe to one within the plan one within the group uh but they can switch between the two and they're both grouped together because they both offer the same thing one's gonna call it premium access although i'm only gonna have the one option within my app so click create there we go we've created a listing we have an apple id for it and we have a product id as i say the product id is what we're gonna use to actually access it within the app so this cleared for sale button um we don't have to worry about right now but that means that when when the app gets accepted it is actually available for sale on the app store this subscription duration obviously is how long you want the subscription to last you have a bunch of options here i'm gonna go with one month okay now we have our prices um we can click add that's going to save our changes so i'll do that i'm going to click add and there we go so we have a starting price um so i'm going to start mine off obviously in in pounds so you can choose your price i'm going to choose 6.99 any price you want there's a lot of different options you can't actually put in your own exact price you have to choose from all these different options but there are a lot so it covers pretty much every single price point all the way up to 809 pounds which is mental um okay so yeah 6.99 in pounds i'm going to click next and it's actually now going to set up the different prices in a bunch of various currencies so as you can see here um these are all in us dollars and it's 699 839 699 and so on so if you wanted to be specific and change say a united states um 6.99 you wanted to change that because obviously 699 dollars is less than 699 pounds it's more like 8.99 you'd want to go in here and make that make those changes yourself now unfortunately you do have to change every single one even though i had to do that with my app i had to change 174 of them and it took bloody ages but yep that's that's how you do it so we're going to click create once you're happy and there we go we now have our starting price so now we have a bunch of different options here for introductory offers for new subscribers uh perhaps like a seven day trial or or a discount or something for the first month as you can see the types you can have is pay as you go pay up front or free um but i'm not going to bother with adding any of those if you do want to this is where you would do it and also promotional offers so for example discount codes and so on which you might want to add here so that is where you do it but i'm not going to bother with that i'm just going to set up the actual subscription okay so now we can get out of this subscription pricing window and we have this option for localizations so uh the name and description for your in-app purchase in different localizations if you want to set them so i'm only going to say english uk that's all i have for my real app as well but you can set as many as you like but you do need to have at least one so obviously the first one is the subscription display name to the actual name of it on the store so i'm going to set mine as rn iap test premium access subscription is going to be one month premium access uh to the app okay you can set that to whatever you like and again there are different rules and guidelines you can follow in order to do these properly and you can find great resources about them but really these can be whatever you like [Music] okay so now we have app store promotion so if you want extra promotion for the in-app purchase you can add an image here i'm not going to do that now with the last thing we have here is this review information which even though i'm not going to be submitting this to the app store in this video we still actually need to provide a dummy screenshot here so that this missing metadata goes away and we can actually test the in-app purchase because uh if you don't do that then you can't actually test it so i'm i'm just uploading the same screenshot i used in my other app to as a demo um but once we got that i'm going to add a little review note saying [Music] testing in-app purchase but obviously when you if you actually submit it for review you're going to want to give as it says here additional information about the in-app purchase to help with the review and the screenshot should actually be a helpful screenshot of the in-app purchase in the actual app but for testing that doesn't matter so i click save and i'm still getting this missing metadata and i can see a message up here that's actually saying we need to add a localization to the subscription group which i forgot to do so i'm gonna add that here uh english uk subscription group display name premium access and we're going to use the app name there we go let's click save here and now we should see if we go back to the in-app purchase it now says ready to submit which is the state it needs to be in in order for us to actually query it from within our app when we're testing okay so we're now at the point where we can start writing some code so i'm just opening up the newly created react native project in vs code i'm going to do everything inside app.js for the simplicity of this tutorial but you may if you already have your app you may know where you want it already but as i say everything's gonna just go in myapp.js because i want it to all happen as the user loads up the app so for this coding part of the tutorial i think it's important that you can actually see what's being typed so what i've done is i've switched the virtual machine to scaled mode which has stretched out the window to fill the full screen but obviously since the stretch the resolution it doesn't match it's a little bit blurry so yeah i'm going to start from a blank app.js and i'm going to import the stuff i need so we have to import react uh use state and use effect from react also i'm going to input a few things here say style sheet text alert view button should be it from now from react native let's get our export default function app and for now i'm just going to return view with some text that says i hate programming which is how i was feeling throughout the entirety of adding in-app purchases to my app and then i'm going to add my style sheet so it's con styles equals stylesheet.create in here i'm going to make a container and give it a flex one let's have a black uh background so background color hashtag zero zero zero oh god i forget i want a mac virtual machine the hashtag isn't where i think it is oh god where the bloody hell is a hashtag on a mac keyboard i have no idea okay apparently it is alt three yeah there we go um hashtag zero zero zero uh black background i do align items center and as well justify content center just a basic uh container there so that is pretty much what you'll find in your default uh app.js now i'm just gonna install the uh dependencies that we need so i'm gonna change directory into the project and i'm gonna do npm install uh save react native iap okay so once that's been installed you can see here on the getting started guide that for ios we then need to do your standard pod install um to actually link the package and then for android you have all this extra stuff i will be doing a tutorial on android as well um but i'm not going to be covering that here okay so i'm just going to cd into the ios directory and run npx or install and yeah that should just run through and set up all your dependencies and the pod files and so on and do everything for us okay so once that's done that is it for our dependencies that's all i'm going to be installing for this so we need to import it and i'm going to do that by just typing in import iap from react native iap right and now from react native we actually need one more thing uh it's going to be the platform apis that's going to allow us to use the following function create a constant called items and we're going to set that equal to platform dot select and what that's going to do is check if it's android or ios and then select um something to assign this variable to based off the platform so i'm going to set this to an object which has a ios key and an android key the ios key is just going to be an array and the android key is going to be an array so if you are making an android app um you're going to want to put your android product ids in here i have none for now so i'm just going to leave it blank but uh for ios remember that i set it up as rt underscore 699 underscore 1m okay so that is going to select our products and set them equal to items okay so now within the app i'm going to do a const and i'm going to have purchased [Music] and set purchased this is going to be a ustay tuck so equals use date and i'm going to set it to false by default so it's just going to purchase is just going to be a boolean which we set through set purchase and by default it's going to be false because we're assuming that they haven't purchased it until we check and verify that they have okay so now i'm going to use another hook called use effect and this takes a callback function i'm going to do an anonymous arrow function and then the second argument is just going to be a blank array because this will just mean this runs as soon as app.js gets loaded we'll run straight away and we'll only run once now let's go on to the actual code that we need the first thing we need to do is actually initialize a connection to the stores i'm going to do iap dot init connection okay and i'm gonna just in case of an error i'm gonna do dot catch um i'm not gonna do anything with the error for now uh and then i'm gonna do dot then so once we've initialized the connection i'll call this callback function and for now i'm just going to do console.log connected to store to store and let's actually say in the catch let's just do console.log uh error connecting to store obviously you can do alerts and say to user hey like something's gone wrong whilst connecting okay but once we've initialized our connection what is the first thing that we might want to do well we actually want to grab all our purchases from uh the app store so we can display them within the app and allow a user to select them so to do that we have a very simple function called iap dot get now we have get uh products and get subscriptions so since mine is a subscription i'm gonna go for get subscriptions this is going to take the items array that we've already initialized so this right here and again i'm just going to do a dot catch and i'm going to do console.log error finding purchases and then we'll do a dot then we'll have a res and this res is going to contain all the details about all the different products that we have i'm going to do another console.log and say uh dot products and actually up here i'm going to set up another state called const products and set products uh equals use state and by default this can just be an empty object okay i'm gonna do set products uh res and console.log for now products let me run this on my actual device and see if that works there we go as you can see the ui needs some work the text is there but it's let's just say it's not where we need it to be but that doesn't matter because what we're interested in is the output in the console and interestingly it's uh succeeded in connecting to the store and getting products but the products we've got is an empty uh object what it actually is uh is i was console login the product state but from within this callback function so it's actually console logging it uh as the state that it was when the callback function was created um so that doesn't actually work but if we console.log this res well you can actually see uh now we're actually getting all the details about our purchase so the currency uh the description one month premium access to the app you have no discounts introductory price and so on price product id okay so that's excellent so that means that uh subscription has been set up correctly and we can get it through the app so um let me get rid of the console log for the products so now let's actually display it in the app so obviously it would first help to add style equals styles dot container to the view and then text let's just make a quick rule in a style sheet here for the uh let's just call it text and i'm gonna do color white because we have a black background font size is going to be let's just go with 30 for now obviously i'm not going to go over making this responsive or anything like that but this is purely focused on getting a basic implementation of the actual in-app purchases if you did want to make it responsive obviously don't use 30 user percentage of the device screen yeah that'll do for now and i will just finish it off by adding style equals styles dot text up here okay there we go so we have this wonderful looking app that says i hate programming let's change the text so how about we actually output the name of our purchase we can do that by uh using curly brackets to indicate that we want to add a javascript object and then uh access our products array which is the state that we set and within there we can access the title so now since this is an array we want to access the correct index uh index zero for me since i only have one in-app product okay let's see if this works and there we go you can see that uh now it's outputting rniap test premium access which if you remember is the subscription display name that we set here okay but that is not actually great because say if the products haven't loaded by the time that this return function goes then since we're accessing or trying to access this index if it doesn't exist it's actually going to throw an error so we need to avoid that and we can do that by adding an if statement and saying if products.length let's say is more than zero then we will do this because then we know that we've fetched the products and we've added them to the list if not then if still loading we can just return some more text so i'll just copy that and say fetching products please wait [Music] okay so there we go so now if it's still loading it's going to display a nice little message to the user um it's going to be quite a sharp change so as soon as the products are found it's going to instantly change so you could use like the reacts animated view to fade it in and make it look a bit nicer but again that's all totally up to you um but this way it's not going to crash through the app by trying to access something that doesn't exist so um in the app which is something you find out the hard way if you try to um submit it without it apple likes you to give the name of the subscription price um and what they actually get for purchasing it and obviously the duration so what i'm going to do here is add that in so i believe from this output here subscription period number one and subscription period unit month you can obviously extract your actual period which is going to be useful if you have multiple different um subscriptions but i'm just gonna uh put it in manually i'm just gonna say one month and then the price do that we're going to go into the products zero again and this time we're going to grab localized rice this should hopefully display the price to the user in their local currency which is nice and i will obviously apply the uh text style as well there we go as you can see on the app uh premium access one month and 6.99 in pounds so now we have the name and the duration and the price next thing we should have really is is the list of features that come with the subscription so i mean obviously this isn't really uh what this tutorial is about um i'm sure you can come up with this on your own but i just thought i'd make it so you could theoretically submit it if you wanted to um because if you submitted it without uh this information then apple will likely reject it so the first thing i'm going to do is i'm just going to add a self-contained view just because i i am picturing like a little you know divided line between the name and the and the price and then the details don't know why i just fancy one give it a height of four and i'm gonna make the background color white and obviously i need to give it a width of let's go with 50. so yeah you can see it in the app now it's just a little line um i'm also going to update the style slightly and give the text uh padding of say five now i'm gonna make a very very very very very basic uh table which is just gonna be done by another view and the style for this i'm just going to do here is going to have a background color which is going to be an rgba value so we'll have like a slightly transparent uh gray uh i'm gonna give it like rounded edges with a border radius of 10 and within this i'm going to make some text i'll make it i'll make another style here called a small text which is just going to have maybe a size of 16 and i'll remove the padding bottom okay and this text can just have the styles.tx file and i'm just going to say features okay so i'm going to make another text and i'm going to give that the uh styles.small text that i just created and within here i'm just going to make up a list of things because the app obviously doesn't do anything so i'm going to say ad free access i'm going to have a little bullet point here as well using this javascript object and if we do we do backslash oh god how do you do a bloody backslash in uh in mac uh alt seven no alt shift seven alt shifts right alt shift seven no that's not a oh god right control shift seven i mean i've literally generated almost every possible feasible symbol apart from a backslash at this point including a bloody apple logo somehow i cannot find out where it is i'm just going to bloody copy and paste right there we go so once you've got your backslash you're going to type u and then 2b24 and that should give us a yeah a bullet point and that doesn't look too bad at all now uh obviously at the end of that i want a new lines okay and now let's just fill in a few more completely made-up features 1000 wizards tokens legendary dragon skin right sounds like the kind of crap you might uh pile into a subscription so there we go that's the basic style that i'm going to go for um one more thing i'm just going to give this a padding of 10 and say a margin top of ten move it down a little bit yeah uh make it bit more okay yeah now before i get too above bog down in the styling i'm going to stop there and leave it at that so there we are we have a basic styling for our app um and that's very acceptable i would say so now let's how do we actually purchase it outside of that table uh i'm gonna add just a regular react native button and now give it a title of purchase okay and then on press well what do we need to call here so what i'm going to do is give it a function just so we know that impression is actually working um it's going to console.log rest and also we're gonna call iap dot request subscription and then we're gonna pass in the product id so obviously we can get that from products xero 0 product id so let's actually try that out so if i press this purchase button and give it a few seconds there we go we actually get a real pop-up and all of that is taken care of for us you can see that the logo of our app obviously i haven't set one is just the default react native uh thing we have the name which the first name i believe is the subscription group name and then underneath that is the um individual name i believe and yeah you can see the price 6.99 a month and the account that you want to subscribe with now if i was to actually click purchase nothing would happen because we're not actually listening or changes uh to a purchase within the app so let's set that up right now now within the use effect outside of the code we've written so far we're going to add a purchase update listener and i'm just going to make it a global variable outside of the function so i'm just going to call it uh purchase updated listener and i'm also going to make one called let purchase error listener so we can handle any errors okay so we're just going to do purchase updated listener equals iap dot purchase updated listener and what that's going to do is once a purchase has been made it's going to call this function and it's going to return the purchase i'm going to take that purchase and pass it to this function and i'm going to run this in a try catch block so what we're actually going to do is make a new cons called receipt and that's going to be equal to purchase dot transaction receipt so let's see if this actually works uh and we'll make we'll console log the receipt and then i guess we'll set purchase to true let's realize it says set purchase instead of set purchased but that's fine i'm just going to set it to true okay now obviously you in practice you don't want to set it to true here what you actually want to do is validate the receipt and this is the annoying point of the tutorial where people just say oh send the receipt to your backend and do the validation um which is obviously not very helpful i will go through that but for now i'm going to set purchase to true as soon as this updated listener is called and also uh print the receipt so we can see what it actually looks like um but let's go down here and return different things based on whether they purchased it or not so i'm going to make a new if statement i'm going to say if purchased if the user has actually made the purchase um and else then it's going to run the code here that we've already written where it fetched says this fetch in the products and then outputs the products okay right so if purchased so i'm just going to return something random but what you would probably do is say if using react navigation you turn you'd return your app navigator and that way they have access to the entire app from there or you know just unlock the content that um the subscription offers so this subscription unlocks the entire app because without it you can't see anything but yours may only unlock say a certain section of the app so um use this purchased uh boolean uh to check whether or not the user can actually access that in this particular session so i'm just going to return something very basic here style equals styles dots uh container text welcome to the app and i'm just going to throw an image in there so i'm just going to return this uh image of a dog because uh i'll be honest i would pay a subscription to just see images of dogs so we'll just add this as the source require dot slash dog dot jpeg obviously we need to import image from react native there we go there is my app right so let's test this out to do this we're going to need sandbox users so head over to app store connect on the home page click the users and access tab now click sandbox testers down here and click add so you're going to have to actually have an email that apparently isn't already associated with an apple id and fill in the information for them here and then click invite okay so i've just made a brand new gmail account for uh the purposes of making a sandbox tester and the email is more bloody testing at gmail.com so i'm going to add that here now you're going to set a password for the tester secret question secret answer date of birth and the region okay so once you have all that click invite now on the email you should have this verify your apple id let's click verify now now you have to enter your password and this is the password that we just created and once you're logged in it should say email address verified so uh on the app store connect this should now be there so now we have the sandbox user actually signed up what we can do is click purchase within the app and it's going to ask us to sign in with the apple id so we're obviously going to sign in with uh the sandbox id we just created okay so i'm just gonna click ok and if we entered the details correctly we should get the purchase pop up in a few seconds now bear in mind the sandbox test environment um can be very slow when i was testing my real app sometimes it would take like a full minute after i pressed the button sometimes for the purchase window to pop up and i was thinking jesus my app is so slow but it actually once it's released this is fine it's just the test it's just the test environment as you can see it's popped up now so yeah we've signed in um it says uh testing purposes only we won't be charged i'm gonna click subscribe and i'm gonna enter the password okay let's click subscribe we get the lovely little uh noise and hopefully in a few seconds there we go so that took about 30 seconds after the purchase actually went through but now he says you're all set purchase was successful i'm gonna click ok and there we go welcome to the app and the lovely picture of the dog now if we take a look at our console we have a wall of text that is the receipt um which we need to send off to the back end which as i say it's a mysterious thing that a lot of other tutorials kind of just expect you to know what to do but if you don't then that's a little bit worrying so what is this back end well the way i'm going to teach you it is using firebase uh serverless functions there's a couple ways to do it obviously you could maybe set up your own server perhaps using a google cloud vm instance or something to be honest i think renting out an entire server uh just to run like one or two functions is a little bit overkill so that's why firebase serverless functions are perfect um obviously you get the free trial and it's completely pay as you go and it's uh if you do go over that and it scales to the amount of users you have to say that your app has 10 users finally you know you're going to be you're not going to be paying anything uh everything's going to be fine but then your app suddenly skyrockets to you know 10 000 users uh then it's fine there's no worries you don't have to change anything you just get as much um stuff as you use so that's the way i'm gonna do it with firebase serverless functions so yeah instead of uh console log and receipt because that isn't really useful information and we're not going to be setting the purchase to true right here because that will set every single purchase to true what we want to actually do is validate the receipt basically checking if it's valid and also checking that the purchase hasn't expired obviously they've just purchased it so it hasn't expired um but we're going to check anyway also we need to check when we load into the app if they already have a purchase on the account that they signed into and if the subscription is still valid then we're going to let them into the app if it isn't and obviously we're not and we're going to say your subscription has expired please um subscribe again to continue using the app so what we need to do here i'm going to add a little to do is validate receipt now i'm going to do that in a second the first thing i'm going to do is create some more code here which is going to get previous purchases and then we'll validate those as well right so what i'm going to do is um after we initialize the connection and underneath the get subscriptions i'm going to do iap.get purchase history this isn't going to take any arguments but again i'm going to do a dot catch so yeah i guess what you should be doing here is uh passing the actual error that we get from the catch and alerting uh the user but i'm not gonna be doing that here what i will do is another firework um you dot then so once we have got purchases obviously we want to pass them to this function and i'm just going to call that res again and i'm going to do const receipt equals rares res.length minus one so what does this mean uh this means the most recent receipt because for my purposes uh having one in-app purchase which is the uh monthly subscription um they might have multiple uh previous receipts but we just want to get the latest one so we can see uh whether that is valid or not now obviously if you do have multiple in-app purchases this might be slightly different but this will be fine for now and from that yeah we want to grab the transat uh transaction receipt so we're making a new variable called receipt setting it equal to the latest transaction receipt so i'm going to say if receipt so if an actual receipt exists then i'm going to call a function called validate and nope vs code i don't want that thank you and call a function called validate and i'm going to pass it the receipt data but obviously validate doesn't exist at a minute so that's something i will do in a second uh but for now i'm just going to do console.log receipt and just check that it actually prints something out yeah if we reload the app here you can see that it's showing the actual subscription and then is printing the receipt here so you can see that obviously that doesn't come from the purchase update list next they haven't purchased anything but it's coming from the get previous history and that's the receipt id but the app doesn't actually update so um what we will want to do is in the validate function i guess uh say set said purchase true so let's actually make this validate function i'm going to define it up here i'm going to say const validate equals and it's going to take in the receipt now there is good news that is uh with the react native iap library or ios you actually don't need a backend to do receipt validation they have a function which will do it for you and make all the necessary calls and do it for you which is great so i'm going to show you how to use that uh but then i will also actually set up uh the back end using just a serverless function and show you how you can do that yourself okay so what i'm going to do is say const result equals a weight and yes this needs to be an async function because uh we have to wait for this result to come back and this is going to be iap dot validate receipt ios so this function as you can see here takes two arguments it's going to take receipt body and it's going to take a boolean so the receipt body uh takes the following format it's going to be a object which i would define now the const receipt body equals and it's going to have receipt data receipt dash data also password so what are these two things well receipt data is just going to be the exact receipt that we pass in up here so we can just put that there and the password is actually something we need to do on app store connect okay so uh back on the in-app purchases section of app store connect before we actually click on the individual purchases we have this option app specific shared secret which is a unique code to receive receipts for this app so to renewable subscriptions so we click generate and there we are so unique code so don't share it with others obviously i'm going to delete this uh app after the video so that's why it's not blurred but yeah this is unique code so don't go sharing it with others um and this is the password so i'm just going to put it there in plain text okay so that is the first thing we're gonna pass is this uh receipt body second thing is this boolean is test so is it a test receipt or not now the actual thing that you're supposed to do is first i believe uh check with a non-test uh so set that to false and then if that fails trying again by setting it to true um but for the purposes of this video i'm just gonna default it to true uh once again i'm gonna do dot catch and then i'm gonna do dot then this should uh return us a receipt so i'm going to have that as a argument here for this function and what i'm going to do is i'll put this in a try catch block so let's um print out this receipt and see what we get okay okay so we get yet another wall of text um which is not very clear at all so yeah environment sandbox latest receipt id which is what we've seen before and then we have a lot of latest receipt info um expires at this date expires day in unix timestamp uh purchase date product id price all sorts okay so that's great it's working we are validating the receipt we know it's valid and we have the expiry time so we can work out when it will expire okay so there's not console log it let's make a constant called renewal history i'm gonna make that receipt dot uh latest receipt info i'm gonna make a new variable called let expired and that's gonna be equal to a expression which is gonna to be date.now the current date in uh the actual unix timestamp um more than expiration so is the current date greater than the expiry date in other words is it expired so this will be set to true if it's expired it'll be set false if it isn't expired what we can do with that is um obviously an if statement if it isn't expired then i'm just going to set purchase to true if it is expired let's just alert the user i'm just going to say purchase expired your subscription has expired please resubscribe to continue using the app oh obviously i didn't actually set the expiration let's do that right now i'm going to do const expiration equals renewal history and we're going to slice the latest renewal history that's we're going to renewal history.length minus one and dot expires underscore date underscore ms there we go so yeah that's the expiration date which we're checking here let's refresh the app and see okay and there we go within a few seconds it has a valid the purchase and his letters in so it might be worth um displaying a check-in purchases message because otherwise the users are gonna be you know thinking why is it showing me this and they may even try to purchase it again um which you obviously don't want maybe a checking state or perhaps validating would be a better way to say it i'll say false start with so when the validate is called and it's going to say set checking true okay and at the end of this i can just say set checking say set checking false okay and that will go in the dot then so it actually happens once we've received the results uh and then let's add an if statement for that down here so we have the if purchase is going to return this but we'll first need to check so i'll just do if checking first and then else then all this can uh go because we'll have to check every time we use the app so i'm just gonna gonna cut all that and stick that in the else statement and then in the if check-in let's just say checking for previous purchases right and we're actually going to set it to true by default and then obviously set it to false one after the validation has been done so then it says check in first and then displays the picture so let's reload the app here you can see checking for previous purchases and now we're in instead of confusing us by showing us the purchase if i sign out of the account so i don't have a purchase um by the way you can do that by in your iphone set and scroll down to lucy app store and then at the bottom it should say sandbox account i'm just going to sign out of it and relaunch the app okay so now it's asking me to sign in and this actually brings us to an interesting exception what if the user presses cancel they don't want to sign in at this point well if we do that then we're going to get a unhandled promise rejection so in this get purchase history catch let's just uh set uh checking false at this point so that way they're not stack uh forever if they don't sign in it will take them to the the purchase page right so i'm just reloading the app and as you can see it's checking for previous purchases and i'm saying your purchase has expired and the reason for that is because this is obviously a test uh service and the subscriptions don't actually last for the true values because it wouldn't be great uh if your subscription when testing actually you have to wait a month for it to naturally expire the subscriptions have a really short duration and i believe they renew five or six times and then they expire now you might be thinking well how do i make it automatically resubscribe and it actually does um the only reason why it's expired like that is because as i say in the in the sandbox service apple cancels the autorenewing after six times um so it has actually renewed six times and the app has been working fine so you don't have to worry about writing any more code to handle uh auto subscribing so if i put in the password here uh wait a few more seconds there we go okay it did take a little while uh but we click okay and as you can see nothing happens because if you remember we haven't added the validate receipt to this yet so what i'm going to do is again just do if receipt then validate receipt okay and there's one more thing i'd like to add to this for now and that is that purchase error listener okay and this is various areas that can occur when the user does something like that maybe they can sold or something just doesn't work so it's good to have this listener so the app just doesn't crash or something so if the user cancels the purchase it will actually throw an error um which we can listen for here that's going to have the response code of two now for me when a user just simply clicks the cancel button i don't really want to say a user cancel i don't want to give them alert or anything i'm just going to leave it so i'm just going to say if error response code um is equal to two as a string then uh this is going to be if the user cancels and i'm gonna do nothing um so if you want to handle that in some other way you can do i'm not going to uh instead when there is a different error i'm just going to do an alert i'm just going to say error and then for the actual text i'm gonna say there has been an error with your purchase and then error code equals and i'm going to add in error and slice out the code okay and there we go we're now handling uh all different types of errors and speaking of error we're actually getting one here because there's too many many things and obviously we need uh the end parentheses to go there there we go that is the code now this works you could take this and use it for your ios app and it would work um i will show you now how to instead of using the uh validate receipt and here i'm going to show you how you could do that in your own back end okay so we have this great code which uses the validate receipt ios function from the react native iap library which is fantastic but um it's probably recommended that you actually have your own backend that does this for you backing code is very very simple and i'm going to show you how to set that all up so we're going to be using something called firebase serverless functions which is a service from google and we don't have to rent out an entire server all we do is basically write however many functions we want and then we can call those functions through a simple request and get a response back we don't have to rent out an entire server to do that we just basically use what we need so i believe with these firebase functions you actually get three up to two million invocations of the function so you can run the function up to two million times a month for free and then is 40 cents by the looks per million okay so what we're going to do is we can go to firebase.google.com and click get started now you're going to want to sign in with your google account so yeah i'm going to sign in with the uh the more bloody test in gmail.com account i made uh yesterday for the first part of the video but uh i've already forgotten the password so i just got to reset it real quick okay so now i'm in this is a brand new firebase account that i've just logged into so once you've logged in you're gonna click create a project project name i'm just gonna call it receipts validation okay and then accept the terms click continue so i'm actually going to turn it off the recommended is to keep it on uh but i'm turning off because i'm just not going to need it and then create the project so now it says your new project is ready i'm going to click continue okay so before we can actually get started and use uh the functions we actually have to go to console.cloud.google.com and set up our billing account because even though uh we may just be using the free trial we're not actually gonna probably be charged anything we still have to add our billing account that's good so just click add billing account and then just go through this you will need to put your card information here okay so once you've done that you should say welcome thanks for signing up free trial includes 300 in credit spent over the next 90 days and then you're done we don't need this uh google cloud platform anymore because now we actually have the billing account and annoyingly we're actually going to need to change from the spark free plan to the blaze pay as you go plan now the reason for that is if you come here and you can see the free spark plan is limited to the node js8 runtime node.js 10 or later requires the pay-as-you-go plan so yeah if you want you can just go into the package.json and change node to eight because version eight can you just use the sparkfree trial but i'm just gonna change to pay as you go because you still get access to the free quota which um i think i'm quite unlikely to go over and even if you do you only pay a tiny bit because you're paying for what you use the reason why we had to set up that cloud billing account is because that's where this guess builds to so um now we're going to click purchase and there we go if you want you can set a budget alert i'm not going to do that but now we have this a plan so what we need in here uh is we're going to click develop and then functions we're not going to use any of the rest of these just the functions and it brings us to a completely blank page because we haven't actually made a function yet so we're going to click get started and it gives us a little get started instructions so the first thing you want to do is open a terminal i'm just going to do this within the terminal inside of vs code in a new directory for the firebase project just copy that and run it and it will install it globally for you and then so the first thing you actually want to do is type firebase login and click yes it's actually going to open up a page in your default browser and ask you to log in right so once you've logged in uh you're gonna click allow here and it's gonna say it's successful we can close this window and now back in the terminal it says uh success we are now logged in it's gonna clear the screen and the next thing we're gonna do is type firebase init to initialize a project uh yes we're ready to proceed we want to scroll down to functions and then press space to select and enter to confirm the choices and we're going to use an existing project because we've already made one on the firebase website receipt validation select that we want to do this in javascript i'm going to click enter we do want to use eslint to catch probable bugs and we do want to install dependencies with npm so that's going to run for a few seconds and set everything up once that's done it's going to say firebase initialization complete and we've got all this new stuff so we have this functions and inside of there we have node modules and an index which has a basic function so i'm going to get rid of the test code there and just show you if you've never seen this before how to actually deploy your first firebase function we'll do a a really quick hello world just to get used to it and then we'll get in with the main programming so to make a function we just do exports dot and then the name of the function i'm just gonna have hello world i'm gonna set that equal to functions dot https dot on and i'm gonna do on request this is going to be equal to a function which is going to take uh request and response okay all right and then within this function we can take whatever data the user is sent to us and return a response so we can just say response.send which is a function we can get access to hello and some text now it's time to actually deploy our function and see if we can access it so we're going to type firebase apply now this is going to send it off to our firebase and we're going to be able to access it remotely now it should be noted that for testing you can run firebase serv which should open it locally but i'm not gonna do that i'm just gonna send it off to firebase so we can see if it works okay so that has completed so if we go back to our firebase click functions we can see that we now have this uh function as appear hello world and we have this link to demonstrate this really basically i'm just going to do it in the browser uh let's see what happens if we just go to this link or we get a response back straight away and saying hello how do we actually get access to the users request we'll have another property here we'll just say you and the value of that can be equal to request dot query dot text this time i'm going to run firebase serve first to test it so we don't have to wait ages for it to be sent off to firebase in order to test it we actually then get this local host url which we can go to and as you can see now says hello what if we pass if i then um add as a query so question mark text equals nice yeah okay so now we're actually getting the result from the user and we're doing something with it that was just a quick introduction to firebase functions now let's actually make one to validate our receipts so i'm just going to delete this function here and i'm going to do exports dot validate ios equals functions.https dot on call this time it's going to be an asynchronous function and it's going to take in data and i'm just going to call the data d within this function body what we need to do well um if we go over to the apple docs we can see that we need to first obviously get the receipt data we've got that and then send it to the app store through a post request to this url that's for testing or this url which is for production now you might be wondering uh why do we actually have to do this at all as you can see here the reason why we want to use a server for this is because we can't build a trusted connection between the user's device and the app store directly because we don't control either end of the connection making it susceptible to a man in the middle attack basically someone could sit in the middle and see the data we're sending to and from and we don't want that even though we're only building a small app possibly we're just going to do it the right way and use uh this tiny little bit of back end code to just make everything a little bit better so we want to send a post request for testing we're going to use this endpoint for production we're going to use this endpoint but it says here the best way to do this is to first verify with the protection url then if we receive a 2107 status code verify with a sandbox url so obviously i'm just going to be using the sandbox url because in order for me to use this one i'd actually have to get the app published which would probably require me making a sensible app i don't think they're going to publish my one year of this dog that you have to pay 6.99 a month for post request is going to go to uh the sandbox url and we're going to send this request body and in this body we need the receipt data the password which are required and then this optional thank you and you might notice that it's pretty much the same as we sent using the validate ios function in react native iap it's the same data this exclude all transactions is useful for auto renewable subscriptions because it gets rid of the old receipts and only shows you the latest one which is what we will need let's make a cons called data and i'm going to set it equal to json.stringify so let's obviously have receipt dash data that's one of the things we just saw from the docs it would help if i spelled it correctly sheet data which can be d dot receipt data obviously in our program we're going to have to send this and i'll build that out in a second and then password can be equal to the dot password and then we're going to set that exclude old dash transactions and we're going to set that to true for our purposes okay so that's the data we need let's actually get that into the app and what i'm going to do is do console.log data right so i'm going to deploy this because this should allow us to see the actual data that we're sending to make sure it's actually get in there and as is to play in i'm going to go on to the mac and write some code so this was the old code that we had so i'm going to comment all of that out so what i'm going to do here is make a new constant can be called anything you like i'm just going to go with delivery receipt and this is going to be asynchronous we're going to await uh the result of a post request i'm going to do this post request using fetch the end point is going to be our firebase which hasn't deployed yet because it's asking me do i really want to delete the function hello world yes i do now if we refresh our functions the hello world one is gone and we have this validate ios which has its own url which we can copy so in our code we will fetch from this url so the data that we will send along with it um it's going to be inside of an object first thing is headers and we want to make sure that the content type is json we're going to do content dash type application slash json then we need to make sure it's an actual post request so we're going to say method host and now we're going to send the actual audi which is going to contain the data so i'm going to just do this on a new line right we're going to say body and that's going to be json.stringify the key is going to be data and the value is going to be receipt body which is the thing here which we actually built up to using our old function so yeah we're just going to send that and hopefully we should be able to access it let's run this now i'm just going to refresh the code we don't need to worry about the output here at all all we're going to do is go into firebase and click logs and here we can actually see a live console so as you can see all this is when we were updating it here is the output we're looking for we have password and exclude old transactions so that means there's a little mistake with the receipt data um so let's check what we're actually looking for here we're looking for d dot receipt underscore data and in the actual mac code we're sending receipt dash data uh so let's just change that to receipt dash data if we do that it's breaking these two things apart so we can remedy that by if we just access the value like this then it's going to work and then for simplicity's sake we should probably access password like that as well let me just deploy this if we take a look at the output here you can see that now we have the receipt data and the password so everything is actually being sent so what do we actually do with this data well of course we need to make a post request as i say um so let's work on doing that and the way we're going to do that um with this firebase function is we're using node.js and an easy way to make a post request is by a library called axios so i'll need to do is cd into the functions folder because we need to install it into this node modules and just type npm install axios okay once that's installed we're gonna do const axios equals require axios so we're just importing it basically then after we get our data we're going to say const result equals a weight axios dot post then the url of the end point so the sandbox endpoint for us because we're just testing then we just send the data okay and now let's just do console.log result and see what we get right so i'm just going to run firebase deploy right so we're in our console now i do not like the way that the firebase console works it's very confusing everything's on its own little line with its own timestamp and um yeah it's it's not great but you can see what we've outputted is all of this stuff but we're actually getting uh data back so let's um instead of printing out everything let's print result and slice out the data so i'm just going to run firebase deploy okay and refresh the code one more time looking in our console making sure that we click the live button so it actually will update when it gets the data okay and now we have all of this so what we're after in the data is this latest receipt info which uh will return an array which contains an object okay so let's console log that we want uh from within data latest underscore receipt underscore info and we know it's an array so let's just access uh index zero because we're only getting the latest receipt anyway so we can be confident that it's uh index zero and let's console like that and see what we get so refreshing the code let's take another look in the console okay and we have a lot of stuff right and within the latest receipt info we have transaction id original transaction id purchase date receipt creation time what we are interested in is expires date because we want to check is the receipt expired or not so we have this expires date ms which is the date in the unix timestamp that uh the receipt expires we can use that to do some checks so coming back to our firebase code let's get rid of this console because we know this is giving us the data we want what we'll do is define a constant called uh receipt data we'll set that equal to where we were just console login let's do another one called expiry which is going to be equal to the receipt data variable and we want to grab the dot expires underscore date underscore ms okay so that should give us access to that uh timestamp number now to check if it is expired or not we can just use another variable called expired and that can be a nice expression just date.now more than expiry so we don't need to do any if statements or anything this expression will give us a true or false value and then all we need to do is return something back and i'm just going to return a boolean called is validated not is validated sorry is expired and that's going to be equal to the expired so we're getting the data we're um slicing out the data that we want this latest receipt info from that we're grabbing the expires date in milliseconds then we're calculating if it is expired and then we'll return in true or false uh in this is expired so let's save that and run firebase deploy hopefully for the last time okay so the deploy has finished now let's go into our react native code right what i'm going to do from here is a dot then after we've got the delivery receipt which is going to take a value called res and pass it to this function then i'm going to do res.json to convert it to json then another dot then and this i'll just call this one r which can be passed to another function and for now we'll just do console.log r obviously let's just do a dot catch on both of these dot then okay and as you can see we get result expired is true so our code is actually working so now what do we do with this value well we need to check if r dot result dot is expired so if it's true then i'm just going to give the user an alert saying expired your subscription has expired please re-subscribe to continue using the app and then if it isn't i'm just going to do an else and i'm going to set the purchased to true so then the data will actually load and at the end of this we need to set that check in variable uh to false or check in state i should say and hopefully that will actually work so let's reload the code i'll get my phone up i'm checking the previous purchases uh your subscription has expired and now it's displaying the actual in-app purchase i click purchase okay as you can see i spammed the button now i'm going to click subscribe okay so the purchase has gone through let's give it a few seconds there we go you're all set and i was checking for purchases and there we go now it's actually loaded it that's fantastic so if i just reopen the app check for my purchases and there we go it's letting us in so this code is actually working we now have our own backend set up to validate the receipt and send us the result back but all we do in our code is just say well if it's expired you can't come in sorry so that hopefully should be everything you need to know to get a really good start into uh react native in-app purchases obviously you can go into this a lot further change the code add different things as you want them but for now that is where i'm going to leave it and if you have any problems put them in the comments [Music] you
Info
Channel: Euan Morgan
Views: 11,214
Rating: 4.941606 out of 5
Keywords: react native in-app purchases, react native, ios, app development, in-app purchases, subscriptions, in-app subscription, auto-renewing subscription, validate receipts, validate in-app purchase receipt, firebase
Id: 4JLHRV2kiCU
Channel Id: undefined
Length: 80min 52sec (4852 seconds)
Published: Sat Nov 07 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.