0
1
00:00:01,140 --> 00:00:08,430
Now, in the last lesson, we've written the code that's required to trigger a paymentRequest in the payment
1

2
00:00:08,430 --> 00:00:10,600
queue to the Apple App Store,
2

3
00:00:10,890 --> 00:00:17,700
and we specified the product that we want to purchase or the user wants to purchase. And we set up
3

4
00:00:17,760 --> 00:00:19,010
this paymentQueue
4

5
00:00:19,030 --> 00:00:27,150
updated transaction delegate method which observes for any changes in the paymentQueue and lets us know
5

6
00:00:27,420 --> 00:00:31,990
when a transaction is purchased and successful or when it's failed.
6

7
00:00:32,040 --> 00:00:38,250
So, now we are going to create a sandbox user in order to test this without having to pay every single
7

8
00:00:38,250 --> 00:00:39,660
time we test it.
8

9
00:00:39,690 --> 00:00:41,690
So let's go into, again,
9

10
00:00:41,730 --> 00:00:46,020
Apo Store Connect and we're going to go to Users and Roles here.
10

11
00:00:46,140 --> 00:00:49,290
So just click on this dropdown list to head over there.
11

12
00:00:49,560 --> 00:00:57,840
And if you head over to sandbox testers, then you can create some new testers by clicking on this plus
12

13
00:00:57,840 --> 00:01:01,260
button. Now, rather awkwardly,
13

14
00:01:01,260 --> 00:01:09,900
Apple actually enforces very strong data validation in the sandbox user creation and I really wish they
14

15
00:01:09,900 --> 00:01:10,280
didn't,
15

16
00:01:10,280 --> 00:01:16,170
because often, I'm forced to create 10 or 20 of these users. And for every single one of them, you have
16

17
00:01:16,170 --> 00:01:19,680
to fill out pretty much every single field.
17

18
00:01:19,680 --> 00:01:24,640
So it doesn't really matter what you give the first name or the last name.
18

19
00:01:24,660 --> 00:01:31,440
I usually just write something like Test Test. But the email has to be unique and it has to be a real
19

20
00:01:31,460 --> 00:01:36,000
email, which is quite difficult, if you're not a professional spammer.
20

21
00:01:36,150 --> 00:01:39,690
How would you have access to even 10 emails that you own?
21

22
00:01:39,690 --> 00:01:41,090
So here's a trick.
22

23
00:01:41,460 --> 00:01:47,630
If you have a Gmail address that is, say, Angela@gmail.com,
23

24
00:01:47,640 --> 00:01:54,160
this, unfortunately, is not my email because I wasn't there fast enough, need to be an earlier adopter.
24

25
00:01:54,390 --> 00:02:02,100
But if, say, this was your e-mail, then Gmail actually has a really neat thing called address alias, and
25

26
00:02:02,100 --> 00:02:06,590
what allows you to do is just before the at sign,
26

27
00:02:07,050 --> 00:02:12,570
you can add a plus and you can write some things like news letter,
27

28
00:02:12,670 --> 00:02:13,110
right?
28

29
00:02:13,380 --> 00:02:18,410
And you can use this e-mail for all of the news letters that you sign up to,
29

30
00:02:18,570 --> 00:02:22,230
and you can filter on this incoming e-mail address in your Gmail inbox.
30

31
00:02:22,230 --> 00:02:29,070
But even though it looks a little bit weird, it still goes to your e-mail address, your inbox.
31

32
00:02:29,070 --> 00:02:32,710
So Angela@gmail.com's inbox in this case.
32

33
00:02:32,730 --> 00:02:39,510
Now, what I often like to do is sometimes when I sign up to something I'm not really that sure about,
33

34
00:02:39,810 --> 00:02:48,480
you know, say, if I sign up to American Express, right? I will actually sign up with my e-mail, plus the
34

35
00:02:48,570 --> 00:02:51,310
address that I signed up to at gmail.com.
35

36
00:02:51,540 --> 00:02:58,510
And this is a really easy way to know which businesses are selling your e-mails for money and to just
36

37
00:02:58,510 --> 00:03:06,240
a protest. But this is a really neat trick. And this is helpful in our case because now you have an infinite
37

38
00:03:06,240 --> 00:03:13,860
variety of unique email addresses, so you can just keep creating new aliases for every single one of
38

39
00:03:13,860 --> 00:03:14,520
your testers.
39

40
00:03:14,520 --> 00:03:17,130
Now, there's just one caveat.
40

41
00:03:17,130 --> 00:03:24,180
The main e-mail for your e-mail alias cannot already belong to an Apple ID.
41

42
00:03:24,180 --> 00:03:30,030
So, say, if you sign up to your Apple ID with this e-mail address, you can't use an alias on it.
42

43
00:03:30,030 --> 00:03:31,380
It doesn't work.
43

44
00:03:31,380 --> 00:03:38,460
But if you haven't used this e-mail, this Gmail address of any Apple IDs, then you can do this quite easily.
44

45
00:03:38,460 --> 00:03:46,890
Now, another option, if you don't have many e-mails that you can use for your sandbox testers is use
45

46
00:03:46,980 --> 00:03:53,460
something like maildrop.cc, and this allows you to just generate a random mailbox, and it'll be able
46

47
00:03:53,460 --> 00:03:57,090
to receive messages, and you'll be able to verify the account.
47

48
00:03:57,090 --> 00:04:02,760
But you, obviously, don't monitor it and it doesn't have a painful creation process.
48

49
00:04:02,850 --> 00:04:07,970
But what it does mean though is that it is a public account.
49

50
00:04:08,070 --> 00:04:13,350
So if you go to some of the ones that somebody might have already used, say, John@maildrop.cc,
50

51
00:04:13,830 --> 00:04:18,950
then you can see that this has all of the stuff that they've previously signed up to,
51

52
00:04:18,950 --> 00:04:21,000
and there's a lot of spam in here,
52

53
00:04:21,030 --> 00:04:21,350
right?
53

54
00:04:21,480 --> 00:04:26,460
So if you use any of these account on maildrop.cc, remember that it's completely public. Do not
54

55
00:04:26,460 --> 00:04:31,110
sign up for anything that has your private details in it using the service.
55

56
00:04:31,110 --> 00:04:37,590
But if you're using it for just testing, then it doesn't really matter because there's nothing sensitive
56

57
00:04:37,590 --> 00:04:39,600
that's going to be sent to it.
57

58
00:04:39,600 --> 00:04:44,730
So in my case, I'm just going to generate a new e-mail address on our website domain
58

59
00:04:44,760 --> 00:04:52,200
that is called tester134@londonappbrewery.com.
59

60
00:04:52,260 --> 00:04:56,800
And the password, rather awkwardly, also has very strict security rules,
60

61
00:04:57,000 --> 00:05:05,490
so you need one capital letter and some numbers and it needs to be quite long, so come up with some sort
61

62
00:05:05,490 --> 00:05:06,830
of combination for that.
62

63
00:05:10,060 --> 00:05:14,220
And the secret question and secret answer, you can take it very seriously if you want to,
63

64
00:05:14,230 --> 00:05:15,660
but I tend to just write 
64

65
00:05:15,650 --> 00:05:17,080
TesterA.
65

66
00:05:17,110 --> 00:05:18,100
TesterQ
66

67
00:05:18,280 --> 00:05:23,290
because it has to be more than six characters or something like that. And date of birth, of course, just
67

68
00:05:23,290 --> 00:05:25,860
some random numbers. And App Store territory,
68

69
00:05:25,870 --> 00:05:31,190
you should choose the App Store that you're testing device is currently signed into.
69

70
00:05:31,210 --> 00:05:37,630
So, for example, I live in the UK, so my App Store, my native App Store, that my testing device is normally
70

71
00:05:37,630 --> 00:05:43,610
set to is the UK territory, so I'll go and find United Kingdom and add that in there.
71

72
00:05:43,900 --> 00:05:50,170
If your device is normally signed into United States territory, then be sure to select that. And once
72

73
00:05:50,170 --> 00:05:57,790
you're done, go ahead and click save, and you'll have this brand-new sandbox user ready to go.
73

74
00:05:57,790 --> 00:06:05,590
So, now we are ready to run our app onto our physical device which is the phone, and we're going to make
74

75
00:06:05,590 --> 00:06:12,610
sure that the team is selected so that it will side load, and I'm going to plug in my phone through USB,
75

76
00:06:13,000 --> 00:06:20,260
and I'm going to select my device as the destination and run this app.
76

77
00:06:20,270 --> 00:06:25,700
So, now while the app is running, I'm going to click on the home button and I'm going to go into Settings.
77

78
00:06:26,540 --> 00:06:34,370
And inside Settings, I'm going to scroll down to iTunes and App Store, and I'm going to scroll all the
78

79
00:06:34,370 --> 00:06:37,340
way down to the bottom where it says sandbox account.
79

80
00:06:37,580 --> 00:06:43,460
And here I'm going to click on it and a sign out of any previous sandbox accounts you've got going on
80

81
00:06:43,850 --> 00:06:48,010
and I'm going to sign in with that new user that I just created.
81

82
00:06:48,170 --> 00:07:01,370
He was called tester134@londonappbrewery.com and I'm going to enter the password of that
82

83
00:07:01,370 --> 00:07:04,790
user that I set up just now, and click Sign In.
83

84
00:07:05,030 --> 00:07:11,400
So now my sandbox account is showing that my tester134 is now signed in,
84

85
00:07:11,630 --> 00:07:15,940
and I'm going to go ahead and relaunch that app InspoQuotes.
85

86
00:07:15,950 --> 00:07:19,380
Now, you can rerun it from Xcode as long as you haven't force quit the app.
86

87
00:07:19,400 --> 00:07:22,360
This is still a active session.
87

88
00:07:22,400 --> 00:07:28,700
So, now if I click on Get More Quotes, then you can see I get this pop-up "Enter your password
88

89
00:07:28,710 --> 00:07:33,540
to confirm your In-App Purchase of 1 Premium Quotes for 0.99p..
89

90
00:07:33,620 --> 00:07:42,630
So I'm going to enter my password for my test user and I'm going to click Buy. And now, we wait for a
90

91
00:07:42,630 --> 00:07:50,000
little bit, and you can see that I get a pop-up that says, "You are all set. Your purchase was successful" in
91

92
00:07:50,120 --> 00:07:53,720
the app. And in the debug console,
92

93
00:07:53,810 --> 00:08:00,330
I get that print statement "Transaction successful" which means that if you look inside quoteTableViewController,
93

94
00:08:00,350 --> 00:08:07,880
the part where that transaction successful gets printed is inside this if statement, 
94

95
00:08:08,150 --> 00:08:10,780
if transaction.transactionState == .purchased.
95

96
00:08:10,790 --> 00:08:13,640
So a successful transaction, then print this.
96

97
00:08:13,730 --> 00:08:19,730
So,now you can see that we can change the quote inside this block to give the user whatever it is that
97

98
00:08:19,730 --> 00:08:24,710
they paid for: extra coins, extra fish, extra quotes
98

99
00:08:24,890 --> 00:08:28,260
in this case. Then we can implement that right here.
99

100
00:08:28,400 --> 00:08:30,850
So way, it's actually working.
100

101
00:08:30,860 --> 00:08:37,160
Now, there's just one thing to remember that if you make a purchase that's been successful with a sandbox
101

102
00:08:37,160 --> 00:08:47,390
user, that user won't be able to make the same purchase again if your in-app purchase is a non-consumable product.
102

103
00:08:47,510 --> 00:08:53,990
So remember that when we created our in-app purchase Premium Quotes, we created it as a non-consumable
103

104
00:08:53,990 --> 00:08:58,370
product because the users shouldn't need to buy it multiple times.
104

105
00:08:58,370 --> 00:09:05,210
They should only pay once to get rid of the ads or pay wants to get the extra quotes and never again.
105

106
00:09:05,210 --> 00:09:10,650
And the way that Apple implements it is that your sandbox users can only purchase a non-consumable
106

107
00:09:10,650 --> 00:09:13,940
product once in their whole lifetime.
107

108
00:09:13,940 --> 00:09:19,610
They can restore purchases that they bought before, but they can't keep buying the same non-consumable
108

109
00:09:19,910 --> 00:09:20,780
product.
109

110
00:09:20,780 --> 00:09:27,680
So this is why you end up creating loads and loads of test users and sandbox accounts,
110

111
00:09:27,680 --> 00:09:32,260
and this is also why you need some alternative emails in order to do this.
111

112
00:09:32,270 --> 00:09:40,450
So, now we have written the code that implements the basic functionality of creating a new paymentRequest
112

113
00:09:40,460 --> 00:09:46,960
and adding it to the payment queue to ask the user for their password and to purchase that in-app purchase.
113

114
00:09:47,090 --> 00:09:52,540
And we've got this delegate method that listens for when that successful and when it's not.
114

115
00:09:52,580 --> 00:09:59,000
And we created a sandbox user that can allow us to test these payments without having to cover and
115

116
00:09:59,090 --> 00:10:06,030
we can activate blocks of our code when the transaction is successful or when the transaction has failed.
116

117
00:10:06,380 --> 00:10:13,170
Now, once the payments have been successful or they have failed, we need to end our transaction.
117

118
00:10:13,250 --> 00:10:16,250
So we're not still holding onto the same transaction.
118

119
00:10:16,490 --> 00:10:24,020
So inside the if statement when our transaction has completed, we're going to write SKPaymentQueue
119

120
00:10:24,170 --> 00:10:24,620
.default()
120

121
00:10:24,620 --> 00:10:34,100
.finishTransaction, and the transaction that we want to terminate is the current transaction
121

122
00:10:34,520 --> 00:10:42,080
that is in question. And we're going to copy that code over to here as well.
122

123
00:10:42,080 --> 00:10:48,800
And finally, even though we are checking to see if there was an error, we're not actually being very explicit
123

124
00:10:48,830 --> 00:10:50,650
with what the error was.
124

125
00:10:50,720 --> 00:10:57,050
And with SKPaymentQueue and StoreKit it, we can actually get a really accurate description of what the
125

126
00:10:57,050 --> 00:10:57,760
error was.
126

127
00:10:57,770 --> 00:11:01,510
So it can guide our debugging if we do get any problems.
127

128
00:11:01,640 --> 00:11:09,220
So let's use optional binding to say if let error = transaction.error.
128

129
00:11:09,470 --> 00:11:19,400
So if there was an error, if it's not nil, then let errorDescription = error.localizedDescription.
129

130
00:11:19,400 --> 00:11:25,220
So instead of just printing "Transaction failed!" I'm going to move that down here and we're going to print
130

131
00:11:25,580 --> 00:11:29,180
"Transaction failed due to error."
131

132
00:11:29,480 --> 00:11:33,610
And I'm going to insert that errorDescription into here.
132

133
00:11:33,680 --> 00:11:36,990
So, now that's a little bit more comprehensive.
133

134
00:11:37,100 --> 00:11:41,820
And that will be really useful when we do have some payment issues that we're testing.
134

135
00:11:41,900 --> 00:11:47,320
So that, in a nutshell, is how you implement in-app purchases. In the next lesson,
135

136
00:11:47,330 --> 00:11:54,320
we're going to enable the user to be able to access the rest of the premiumQuotes in addition to the
136

137
00:11:54,320 --> 00:11:58,940
free quotes after the purchase has been successful.
137

138
00:11:58,940 --> 00:12:02,230
So for all of that and more, I'll see you on the next lesson.
