0
1
00:00:00,510 --> 00:00:00,840
All right.
1

2
00:00:00,840 --> 00:00:07,200
So, now that we've created the delegate method for our table view so that we can detect when the user
2

3
00:00:07,230 --> 00:00:11,290
presses that last row that gets more quotes,
3

4
00:00:11,340 --> 00:00:17,880
we can call a function called buyPremiumQuotes and it's in this function that we're going to trigger
4

5
00:00:18,000 --> 00:00:19,880
the in-app purchase.
5

6
00:00:19,890 --> 00:00:27,810
So first of all, we're going to create a new constant that is going to record our product ID and that
6

7
00:00:27,900 --> 00:00:34,490
ID is the same as the ID that we put into App Store Connect under Features, In-App Purchases.
7

8
00:00:34,500 --> 00:00:40,050
We've got that product called Premium Quotes and this is the product ID that we want.
8

9
00:00:40,050 --> 00:00:47,920
So I'm just going to copy it over to our code here and I'm going to put it in just as a simple string.
9

10
00:00:47,970 --> 00:00:54,450
Now, this is the ID that we're going to use to hit up the Apple App Store to tell it what we want to
10

11
00:00:54,450 --> 00:00:54,990
buy,
11

12
00:00:55,020 --> 00:01:01,200
and so that the user gets charged the right amount, namely, whatever it is that we've put in in here, and
12

13
00:01:01,290 --> 00:01:07,670
that they can purchase and that the funds go towards ourselves as our developer account.
13

14
00:01:07,680 --> 00:01:12,010
So, now that we've got what we want to purchase, how are we going to purchase that,
14

15
00:01:12,090 --> 00:01:18,030
well, in order to implement in-app purchases, the framework that we're going to be using is something
15

16
00:01:18,030 --> 00:01:25,170
called a StoreKit and StoreKit has all of the functionality that we'll need to implement in-app purchases
16

17
00:01:25,290 --> 00:01:26,910
for virtual products.
17

18
00:01:26,910 --> 00:01:32,370
So once we've added StoreKit, then we'll be able to tap into all of its functions and attributes.
18

19
00:01:32,430 --> 00:01:40,350
So inside our buyPremiumQuotes function, the first thing we need to check is whether if the user can
19

20
00:01:40,500 --> 00:01:46,200
actually make a purchase because if they're on a phone that has parental controls enabled, then we won't
20

21
00:01:46,200 --> 00:01:49,050
be able to get them to make any sort of in-app purchases,
21

22
00:01:49,050 --> 00:01:55,350
and this is the way that Apple tries to keep your kids from running up the credit card bill and buying
22

23
00:01:55,380 --> 00:01:59,810
thousands of dollars worth of in-app purchases in Clash of Clans, for example.
23

24
00:01:59,820 --> 00:02:04,090
So the way to check that is something called 
24

25
00:02:04,100 --> 00:02:09,220
SKPaymentQueue, and this is the queue of payment transactions to be processed by the App Store.
25

26
00:02:09,300 --> 00:02:15,420
And it has a method called canMakePayments, and this method returns a Boolean,
26

27
00:02:15,420 --> 00:02:21,280
so true or false, as to whether if the user is allowed to make payments, and that's exactly what we need
27

28
00:02:21,280 --> 00:02:21,670
to know.
28

29
00:02:21,750 --> 00:02:30,310
So if this returns true, then, in that case, the user can make payments. And if it returns false or rather
29

30
00:02:30,330 --> 00:02:32,750
else, then can't make payments.
30

31
00:02:32,940 --> 00:02:39,060
So it's a good idea while we're testing our app to just put in a print statement that says,
31

32
00:02:39,660 --> 00:02:42,070
"User can't make payments." That we go.
32

33
00:02:42,540 --> 00:02:49,020
But if they can make payments, then we can go ahead and trigger the next step of our in-app purchase request
33

34
00:02:49,320 --> 00:02:51,570
which is to create a new request.
34

35
00:02:51,570 --> 00:02:58,980
So we're going to use a let to create a constant called paymentRequest and this is going to be a new
35

36
00:02:59,010 --> 00:03:05,850
object created from the class called SKMutablePayment which is a mutable request to the App Store
36

37
00:03:06,090 --> 00:03:10,670
to process payment for additional functionality namely in in-app purchase.
37

38
00:03:10,680 --> 00:03:15,330
So this is where we're creating a new in-app purchase request basically.
38

39
00:03:15,590 --> 00:03:24,690
And we're going to specify that this paymentRequest is for the product with productIdentifier of whatever
39

40
00:03:24,690 --> 00:03:30,320
it is that we had up here which is saved under this constant called productID.
40

41
00:03:30,330 --> 00:03:38,040
So we're saying that we're making a request to purchase a new in-app purchase and the product that we
41

42
00:03:38,040 --> 00:03:42,870
want is the one that has the productID that we've specified.
42

43
00:03:42,870 --> 00:03:50,400
And finally, we tap into that SKPaymentQueue again and we grab the default queue and we add this
43

44
00:03:50,400 --> 00:03:52,840
payment request to the queue.
44

45
00:03:52,930 --> 00:03:56,330
So paymentRequest goes in there, and that's it.
45

46
00:03:56,460 --> 00:04:01,520
That's all the code that we need in order to implement our in-app purchase.
46

47
00:04:01,530 --> 00:04:08,520
Now, this is not the end of the tutorial, however, because we still need to figure out how we can detect
47

48
00:04:08,760 --> 00:04:14,880
when a payment has been successful so that we know that we can give them access to the extra information,
48

49
00:04:15,270 --> 00:04:20,070
or that when a payment is failed so that we don't accidentally give them access to all of our premium
49

50
00:04:20,070 --> 00:04:22,910
features, even though they haven't paid for it.
50

51
00:04:22,920 --> 00:04:27,700
So in order to do that, we need to read a little bit about this payment business.
51

52
00:04:27,720 --> 00:04:34,760
So if you hold down alt and click on SKPaymentQueue, there's a quick talk of how this all works.
52

53
00:04:34,770 --> 00:04:39,210
So the summary is that this is a queue of payment transactions to be processed by the App Store.
53

54
00:04:39,210 --> 00:04:46,400
So, of course, you can add multiple paymentRequests to this queue, so you can purchase, you know, five in-app
54

55
00:04:46,410 --> 00:04:49,280
purchases in the same go if you wanted to.
55

56
00:04:49,530 --> 00:04:56,200
And the discussion part says that the payment queue communicate with the App Store and presents a user
56

57
00:04:56,200 --> 00:05:02,530
or a user interface, so a pop up, so that they can enter the password and authorize the payment.
57

58
00:05:02,530 --> 00:05:09,910
Now, to process a payment, first, and at least one observer object which is called SKOaymentTransactionObserver
58

59
00:05:10,720 --> 00:05:17,680
to the queue, and then add a payment object which is what we've done here for the item that
59

60
00:05:17,680 --> 00:05:19,300
the user wants to purchase.
60

61
00:05:19,540 --> 00:05:25,970
And after the payment is fulfilled, the queue updates the transaction object, and then calls the observer
61

62
00:05:25,990 --> 00:05:33,030
so that it tells us that the transaction has been updated and whether if it failed or succeeded.
62

63
00:05:33,700 --> 00:05:39,770
So the next thing that we need to implement is this SKPaymentTransactionObserver
63

64
00:05:40,090 --> 00:05:42,540
and this has a delegate method,
64

65
00:05:42,550 --> 00:05:51,070
so we have to add the protocol of SKPaymentTransactionObserver which contains a set of methods that
65

66
00:05:51,070 --> 00:05:57,690
processes transactions, unlocks purchase functionality, and continue promoted in-app purchases.
66

67
00:05:57,760 --> 00:06:05,170
So that basically means that when we add this observer, then once the payment goes through and the user
67

68
00:06:05,170 --> 00:06:11,530
types in their user name and password for the App Store and it was successful, then we'll get a message
68

69
00:06:11,530 --> 00:06:17,650
back telling us that it was successful, or if it failed, then we'll get a message saying it failed or a
69

70
00:06:17,650 --> 00:06:19,050
whole bunch of other things.
70

71
00:06:19,060 --> 00:06:22,850
So as soon as I add this protocol, you can see we get an error.
71

72
00:06:22,990 --> 00:06:29,000
And it says that in order to conform to this protocol, you have to add the delegate method.
72

73
00:06:29,080 --> 00:06:31,530
So let's get it to add it automatically.
73

74
00:06:31,780 --> 00:06:38,240
And the only delegate method that's required is this one which is paymentQueue updated transactions.
74

75
00:06:38,260 --> 00:06:44,820
So this delegate method will inform us when the transactions have been updated in the paymentQueue.
75

76
00:06:45,130 --> 00:06:52,090
So let's move this down a little bit to the parts where we've got our in-app purchase methods, and we're going
76

77
00:06:52,090 --> 00:06:57,090
to put it over here, and I'm going to just delete this placeholder that says code.
77

78
00:06:57,100 --> 00:07:03,520
Now, remember that whenever you add a new protocol and you want to use a delegate method, you have to
78

79
00:07:03,520 --> 00:07:06,980
declare a class as the delegate.
79

80
00:07:07,150 --> 00:07:14,950
So we want to declare this current class, the QuoteTabVviewController as the delegate who's going
80

81
00:07:14,950 --> 00:07:21,640
to receive the messages from the SKPaymentTransactionObserver when the transaction status changes.
81

82
00:07:21,640 --> 00:07:23,390
So inside viewDidLoad,
82

83
00:07:23,500 --> 00:07:31,050
we're going to add ourselves as the delegate. And the code for this is simply 
83

84
00:07:31,050 --> 00:07:38,790
SKPaymentQueue.default which is the default queue that we're using to process our payment request 
84

85
00:07:38,960 --> 00:07:42,260
.add. And this adds an observer.
85

86
00:07:42,460 --> 00:07:48,980
So notice that when I write .add, there's actually two methods that this object has.
86

87
00:07:49,030 --> 00:07:55,060
One is add observer and the other one is add the payment to be processed.
87

88
00:07:55,060 --> 00:07:59,700
Now, the only difference they have is the names of the parameters. And in Swift,
88

89
00:07:59,710 --> 00:08:01,030
this is perfectly legal.
89

90
00:08:01,030 --> 00:08:06,790
You can have the same method name, but as long as the parameter names for the methods are different, then
90

91
00:08:06,790 --> 00:08:10,080
they are treated as completely separate methods.
91

92
00:08:10,360 --> 00:08:16,870
So, if you're coming from other programming languages, for example, C or C++, this should be familiar to
92

93
00:08:16,870 --> 00:08:17,760
you as well.
93

94
00:08:17,800 --> 00:08:21,030
So the one that we want is to add an observer.
94

95
00:08:21,340 --> 00:08:28,000
And this takes an object that is a SKPaymentTransactionObserver. And by declaring ourselves
95

96
00:08:28,000 --> 00:08:34,570
as conforming to this protocol and implementing the required delegate method, then we are qualified to
96

97
00:08:34,570 --> 00:08:39,150
set ourselves or this current class as the observer.
97

98
00:08:39,160 --> 00:08:45,550
So now whenever any changes happens to the payment transaction, it's going to contact our 
98

99
00:08:45,550 --> 00:08:51,760
QuoteTableViewController and it's going to try and find this delegate method to trigger an update.
99

100
00:08:51,760 --> 00:08:59,350
Now, if you Allt click on this paymentQueue function or search for it in Google or StackOverflow or
100

101
00:08:59,380 --> 00:09:05,650
Apple Docs, you can see that we have a summary which tells an observer, which is this current class, that
101

102
00:09:05,740 --> 00:09:07,950
one or more transactions have been updated.
102

103
00:09:07,960 --> 00:09:12,390
So it gets triggered every single time the transaction status changes.
103

104
00:09:12,610 --> 00:09:19,750
But not only that, the application should process each transaction by examining the transaction's 
104

105
00:09:19,750 --> 00:09:21,250
transactionState property.
105

106
00:09:21,250 --> 00:09:27,530
So this is the transactions that we get back and it has a property, apparently, called transactionState.
106

107
00:09:27,850 --> 00:09:32,890
And if we click on transactionState, it tells us the whole bunch of transaction States we can
107

108
00:09:32,890 --> 00:09:33,740
get back.
108

109
00:09:33,760 --> 00:09:42,020
Namely, one is purchasing, being purchased by the aApp Store. Purchased, so successfully process payment.
109

110
00:09:42,070 --> 00:09:48,510
The money is going to hit your developer account and you are ready to release the premium product.
110

111
00:09:48,730 --> 00:09:52,860
Failed, so the transaction failed and you can check the property to see what happened.
111

112
00:09:53,020 --> 00:09:59,830
Or restored which is where, say, if a user buys a new phone and they download the apps all over again,
112

113
00:09:59,960 --> 00:10:05,000
they want to be able to restore the previous in-app purchases that they've made.
113

114
00:10:05,000 --> 00:10:11,690
So we're going to check for each of these cases in the transaction state inside this delegate method.
114

115
00:10:11,690 --> 00:10:17,320
Now, remember, previously, I said the paymentQueue can contain any number of transactions.
115

116
00:10:17,360 --> 00:10:23,420
So if you were to purchase three in-app purchases all in one go, then all the transactions will get piled
116

117
00:10:23,480 --> 00:10:28,120
into this array of SKPaymentTransactions.
117

118
00:10:28,130 --> 00:10:33,380
So in order to check each of these transactions, we're going to have to loop through it.
118

119
00:10:33,380 --> 00:10:41,590
So we're going to say "for transaction in transactions," and that transactions comes from here.
119

120
00:10:41,720 --> 00:10:46,280
This one is just the variable we're creating to loop through these transactions.
120

121
00:10:46,280 --> 00:10:54,530
And for every transaction in all of the array of transactions, we're going to check if the current transaction
121

122
00:10:54,530 --> 00:11:03,080
that we're looping through .transactionState is equal to .purchased, and that means that it was
122

123
00:11:03,140 --> 00:11:05,030
a successful purchase.
123

124
00:11:05,180 --> 00:11:06,320
So User
124

125
00:11:09,990 --> 00:11:11,730
payment successful
125

126
00:11:14,180 --> 00:11:26,220
Now, else if the transaction.transactionState was actually something like .failed, then in that
126

127
00:11:26,220 --> 00:11:30,270
case, something bad happened and payment failed.
127

128
00:11:30,270 --> 00:11:34,620
Now, this can also include if they click the cancel button and they didn't want to go ahead with the
128

129
00:11:34,620 --> 00:11:35,740
payment anymore.
129

130
00:11:35,940 --> 00:11:42,590
So now we have two if statements, one when it's successful and one when the transaction failed.
130

131
00:11:42,600 --> 00:11:50,130
So let's go ahead and add a print statement to show in the console when we test our app which case it
131

132
00:11:50,130 --> 00:11:50,540
is.
132

133
00:11:50,580 --> 00:11:59,010
So print "Transaction successful!" Print "Transaction failed!"
133

134
00:11:59,040 --> 00:12:05,460
So, now we're ready to test our in-app purchases, and remember what I said before that you have to test
134

135
00:12:05,460 --> 00:12:09,030
it on a physical iPhone or iPad device.
135

136
00:12:09,030 --> 00:12:10,490
It can't be in the simulator.
136

137
00:12:10,500 --> 00:12:15,960
It doesn't work and it won't tell you that it's not working or give you any logical errors.
137

138
00:12:16,080 --> 00:12:20,540
You just have to know that you have to use a physical device.
138

139
00:12:20,550 --> 00:12:27,680
Now, the other problem is that I've set this is in-app purchase for my premium quotes to be .99 cents
139

140
00:12:27,790 --> 00:12:32,040
and I don't really want to pay 99 cents every single time I want to test my app,
140

141
00:12:32,040 --> 00:12:32,490
right?
141

142
00:12:32,520 --> 00:12:34,970
So I don't want to use my normal Apple ID.
142

143
00:12:35,040 --> 00:12:36,400
So what's the workaround?
143

144
00:12:36,450 --> 00:12:42,460
Well, we can create a sandbox user that's just for testing these payments.
144

145
00:12:42,540 --> 00:12:44,010
So in the next lesson,
145

146
00:12:44,040 --> 00:12:49,310
that's exactly what we're going to be doing and we're going to be testing our app and seeing whether
146

147
00:12:49,320 --> 00:12:50,110
if it work.
