Skip to content

Commit 93d70c2

Browse files
in_app_purchases codelab: Dart Server implementation (#1493)
PR with all the changes for the In-App Purchases codelab. This completely removes the firebase-backend and adds the dart-backend. The copy of the codelab document has been updated to reflect all the changes, and this PR shouldn't be merged until the document has been reviewed. I will open it as draft to see if there are any CI issues, and go back and check the whole codelab one more time step by step to see if I missed something. ## Pre-launch Checklist - [x] I read the [Effective Dart: Style] _recently_, and have followed its advice. - [x] I signed the [CLA]. - [x] I updated/added relevant documentation (doc comments with `///`). <- Check codelab document - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-devrel channel on [Discord]. <!-- Links --> [Effective Dart: Style]: https://dart.dev/guides/language/effective-dart/style [CLA]: https://cla.developers.google.com/ [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Brett Morgan <[email protected]>
1 parent 3903aa3 commit 93d70c2

File tree

359 files changed

+4344
-5901
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

359 files changed

+4344
-5901
lines changed

flutter_ci_script_beta.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ declare -a CODELABS=(
2727
"github-client"
2828
"google-maps-in-flutter"
2929
"haiku_generator"
30-
# TODO(DomesticMouse): Use 'const' with the constructor to improve performance.
30+
# TODO(miquelbeltran): Use 'const' with the constructor to improve performance.
3131
# "in_app_purchases"
3232
"namer"
3333
"next-gen-ui"

in_app_purchases/complete/app/.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ app.*.map.json
4545
/android/app/profile
4646
/android/app/release
4747

48-
49-
google-services.json
48+
# Configuration files
5049
GoogleService-Info.plist
50+
google-services.json
51+
ios/firebase_app_id_file.json
52+
lib/firebase_options.dart

in_app_purchases/complete/app/android/app/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ android {
4242
}
4343

4444
defaultConfig {
45-
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
4645
applicationId "com.example.dashclicker"
4746
minSdkVersion 19
4847
targetSdkVersion 30

in_app_purchases/complete/app/android/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
buildscript {
2-
ext.kotlin_version = '1.3.50'
2+
ext.kotlin_version = '1.6.21'
33
repositories {
44
google()
55
mavenCentral()

in_app_purchases/complete/app/ios/Flutter/AppFrameworkInfo.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@
2121
<key>CFBundleVersion</key>
2222
<string>1.0</string>
2323
<key>MinimumOSVersion</key>
24-
<string>8.0</string>
24+
<string>11.0</string>
2525
</dict>
2626
</plist>

in_app_purchases/complete/app/ios/Podfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# Uncomment this line to define a global platform for your project
2-
platform :ios, '10.0'
2+
# platform :ios, '11.0'
33

44
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
55
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
@@ -30,8 +30,8 @@ flutter_ios_podfile_setup
3030
target 'Runner' do
3131
use_frameworks!
3232
use_modular_headers!
33+
3334
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
34-
pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => '7.3.0'
3535
end
3636

3737
post_install do |installer|

in_app_purchases/complete/app/ios/Runner.xcodeproj/project.pbxproj

Lines changed: 17 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33
archiveVersion = 1;
44
classes = {
55
};
6-
objectVersion = 51;
6+
objectVersion = 54;
77
objects = {
88

99
/* Begin PBXBuildFile section */
1010
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
11+
31232B97B81B0FFE3F91E419 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 32EC399CD8FFF4A9FABE4BEF /* GoogleService-Info.plist */; };
1112
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
1213
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
1314
91B69DFA1F97D657D1B74B66 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 53ABA23D4E7C8EC23E2D3EC0 /* Pods_Runner.framework */; };
1415
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
1516
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
1617
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
17-
E43DA72B2627199200DD4341 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = E43DA72A2627199200DD4341 /* GoogleService-Info.plist */; };
1818
E4EE34B826297878004B4DC0 /* Info-Debug.plist in Resources */ = {isa = PBXBuildFile; fileRef = E4EE34B626297878004B4DC0 /* Info-Debug.plist */; };
1919
/* End PBXBuildFile section */
2020

@@ -35,6 +35,7 @@
3535
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
3636
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3737
2B85D05D50E240F1CCA23A89 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
38+
32EC399CD8FFF4A9FABE4BEF /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
3839
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3940
53ABA23D4E7C8EC23E2D3EC0 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4041
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
@@ -47,7 +48,6 @@
4748
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
4849
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
4950
C86631EBF265EF858AFE3BB2 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
50-
E43DA72A2627199200DD4341 /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
5151
E4EE34B526297878004B4DC0 /* Info-Release.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Release.plist"; sourceTree = "<group>"; };
5252
E4EE34B626297878004B4DC0 /* Info-Debug.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-Debug.plist"; sourceTree = "<group>"; };
5353
EA68D4CD820D378B9DF5D7EF /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
@@ -89,12 +89,12 @@
8989
97C146E51CF9000F007C117D = {
9090
isa = PBXGroup;
9191
children = (
92-
E43DA72A2627199200DD4341 /* GoogleService-Info.plist */,
9392
9740EEB11CF90186004384FC /* Flutter */,
9493
97C146F01CF9000F007C117D /* Runner */,
9594
97C146EF1CF9000F007C117D /* Products */,
9695
47D20FC276A4E470F35CCAAC /* Pods */,
9796
BE166FF6C4C1A1730CDDA7CC /* Frameworks */,
97+
32EC399CD8FFF4A9FABE4BEF /* GoogleService-Info.plist */,
9898
);
9999
sourceTree = "<group>";
100100
};
@@ -145,7 +145,6 @@
145145
9705A1C41CF9048500538489 /* Embed Frameworks */,
146146
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
147147
424572DB4B8D34638CEDDB24 /* [CP] Embed Pods Frameworks */,
148-
84562BA058601AD12BCDFEBE /* [CP] Copy Pods Resources */,
149148
);
150149
buildRules = (
151150
);
@@ -162,7 +161,7 @@
162161
97C146E61CF9000F007C117D /* Project object */ = {
163162
isa = PBXProject;
164163
attributes = {
165-
LastUpgradeCheck = 1020;
164+
LastUpgradeCheck = 1300;
166165
ORGANIZATIONNAME = "";
167166
TargetAttributes = {
168167
97C146ED1CF9000F007C117D = {
@@ -197,9 +196,9 @@
197196
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
198197
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
199198
E4EE34B826297878004B4DC0 /* Info-Debug.plist in Resources */,
200-
E43DA72B2627199200DD4341 /* GoogleService-Info.plist in Resources */,
201199
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
202200
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
201+
31232B97B81B0FFE3F91E419 /* GoogleService-Info.plist in Resources */,
203202
);
204203
runOnlyForDeploymentPostprocessing = 0;
205204
};
@@ -230,6 +229,7 @@
230229
};
231230
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
232231
isa = PBXShellScriptBuildPhase;
232+
alwaysOutOfDate = 1;
233233
buildActionMask = 2147483647;
234234
files = (
235235
);
@@ -259,25 +259,9 @@
259259
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
260260
showEnvVarsInLog = 0;
261261
};
262-
84562BA058601AD12BCDFEBE /* [CP] Copy Pods Resources */ = {
263-
isa = PBXShellScriptBuildPhase;
264-
buildActionMask = 2147483647;
265-
files = (
266-
);
267-
inputFileListPaths = (
268-
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
269-
);
270-
name = "[CP] Copy Pods Resources";
271-
outputFileListPaths = (
272-
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
273-
);
274-
runOnlyForDeploymentPostprocessing = 0;
275-
shellPath = /bin/sh;
276-
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
277-
showEnvVarsInLog = 0;
278-
};
279262
9740EEB61CF901F6004384FC /* Run Script */ = {
280263
isa = PBXShellScriptBuildPhase;
264+
alwaysOutOfDate = 1;
281265
buildActionMask = 2147483647;
282266
files = (
283267
);
@@ -381,14 +365,15 @@
381365
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
382366
CLANG_ENABLE_MODULES = YES;
383367
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
384-
DEVELOPMENT_TEAM = 7624MWN53C;
368+
DEVELOPMENT_TEAM = QW3DS6J843;
385369
ENABLE_BITCODE = NO;
386370
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
371+
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
387372
LD_RUNPATH_SEARCH_PATHS = (
388373
"$(inherited)",
389374
"@executable_path/Frameworks",
390375
);
391-
PRODUCT_BUNDLE_IDENTIFIER = com.example.dashclicker;
376+
PRODUCT_BUNDLE_IDENTIFIER = work.beltran.iap;
392377
PRODUCT_NAME = "$(TARGET_NAME)";
393378
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
394379
SWIFT_VERSION = 5.0;
@@ -510,14 +495,15 @@
510495
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
511496
CLANG_ENABLE_MODULES = YES;
512497
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
513-
DEVELOPMENT_TEAM = 7624MWN53C;
498+
DEVELOPMENT_TEAM = QW3DS6J843;
514499
ENABLE_BITCODE = NO;
515500
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
501+
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
516502
LD_RUNPATH_SEARCH_PATHS = (
517503
"$(inherited)",
518504
"@executable_path/Frameworks",
519505
);
520-
PRODUCT_BUNDLE_IDENTIFIER = com.example.dashclicker;
506+
PRODUCT_BUNDLE_IDENTIFIER = work.beltran.iap;
521507
PRODUCT_NAME = "$(TARGET_NAME)";
522508
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
523509
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -533,14 +519,15 @@
533519
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
534520
CLANG_ENABLE_MODULES = YES;
535521
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
536-
DEVELOPMENT_TEAM = 7624MWN53C;
522+
DEVELOPMENT_TEAM = QW3DS6J843;
537523
ENABLE_BITCODE = NO;
538524
INFOPLIST_FILE = "Runner/Info-$(CONFIGURATION).plist";
525+
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
539526
LD_RUNPATH_SEARCH_PATHS = (
540527
"$(inherited)",
541528
"@executable_path/Frameworks",
542529
);
543-
PRODUCT_BUNDLE_IDENTIFIER = com.example.dashclicker;
530+
PRODUCT_BUNDLE_IDENTIFIER = work.beltran.iap;
544531
PRODUCT_NAME = "$(TARGET_NAME)";
545532
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
546533
SWIFT_VERSION = 5.0;

in_app_purchases/complete/app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<Scheme
3-
LastUpgradeVersion = "1020"
3+
LastUpgradeVersion = "1300"
44
version = "1.3">
55
<BuildAction
66
parallelizeBuildables = "YES"

in_app_purchases/complete/app/ios/Runner/Info-Debug.plist

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,9 @@
2323
<key>CFBundleURLTypes</key>
2424
<array>
2525
<dict>
26-
<key>CFBundleTypeRole</key>
27-
<string>Editor</string>
2826
<key>CFBundleURLSchemes</key>
2927
<array>
30-
<string>com.googleusercontent.apps.267794903814-rejjtjrpe3ia81avvoqc3g2ieh7p3eji</string>
28+
<string>com.googleusercontent.apps.556020018095-tbllog3gca3o9vvd3og3kbg0pb598udn</string>
3129
</array>
3230
</dict>
3331
</array>
@@ -65,5 +63,7 @@
6563
</array>
6664
<key>UIViewControllerBasedStatusBarAppearance</key>
6765
<false/>
66+
<key>GIDClientID</key>
67+
<string>556020018095-tbllog3gca3o9vvd3og3kbg0pb598udn.apps.googleusercontent.com</string>
6868
</dict>
6969
</plist>

in_app_purchases/complete/app/lib/constants.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ const cloudRegion = 'europe-west1';
22
const storeKeyConsumable = 'dash_consumable_2k';
33
const storeKeyUpgrade = 'dash_upgrade_3d';
44
const storeKeySubscription = 'dash_subscription_doubler';
5+
6+
// TODO: Replace by your own server IP
7+
const serverIp = '192.168.178.46';

in_app_purchases/complete/app/lib/logic/dash_counter.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ import 'dart:async';
33
import 'package:flutter/widgets.dart';
44
import 'package:intl/intl.dart';
55

6-
const updatesPerSecond = 10; // make sure (1000/updatesPerSecond) is a valid int
6+
const updatesPerSecond = 10;
77

88
class DashCounter extends ChangeNotifier {
99
final numberFormatter = NumberFormat.compactLong();
10+
1011
int get count => _count.floor();
12+
1113
String get countString => _countString;
1214
String _countString = '0';
1315
double _count = 0;
@@ -18,7 +20,7 @@ class DashCounter extends ChangeNotifier {
1820

1921
DashCounter() {
2022
timer = Timer.periodic(
21-
Duration(milliseconds: (1000 / updatesPerSecond).floor()),
23+
const Duration(milliseconds: 1000 ~/ updatesPerSecond),
2224
(timer) => _updateWithAutoIncrement(),
2325
);
2426
}

in_app_purchases/complete/app/lib/logic/dash_purchases.dart

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
// ignore_for_file: avoid_print
2+
13
import 'dart:async';
4+
import 'dart:convert';
25

36
import 'package:flutter/foundation.dart';
47
import 'package:flutter/material.dart';
8+
import 'package:http/http.dart' as http;
59
import 'package:in_app_purchase/in_app_purchase.dart';
610

711
import '../constants.dart';
@@ -43,14 +47,6 @@ class DashPurchases extends ChangeNotifier {
4347
return;
4448
}
4549

46-
try {
47-
await firebaseNotifier.functions;
48-
} catch (e) {
49-
storeState = StoreState.notAvailable;
50-
notifyListeners();
51-
return;
52-
}
53-
5450
const ids = <String>{
5551
storeKeyConsumable,
5652
storeKeySubscription,
@@ -121,23 +117,36 @@ class DashPurchases extends ChangeNotifier {
121117
}
122118

123119
Future<bool> _verifyPurchase(PurchaseDetails purchaseDetails) async {
124-
final functions = await firebaseNotifier.functions;
125-
final callable = functions.httpsCallable('verifyPurchase');
126-
final results = await callable.call<bool>({
127-
'source': purchaseDetails.verificationData.source,
128-
'verificationData':
129-
purchaseDetails.verificationData.serverVerificationData,
130-
'productId': purchaseDetails.productID,
131-
});
132-
return results.data;
120+
final url = Uri.parse('http://$serverIp:8080/verifypurchase');
121+
const headers = {
122+
'Content-type': 'application/json',
123+
'Accept': 'application/json',
124+
};
125+
final response = await http.post(
126+
url,
127+
body: jsonEncode({
128+
'source': purchaseDetails.verificationData.source,
129+
'productId': purchaseDetails.productID,
130+
'verificationData':
131+
purchaseDetails.verificationData.serverVerificationData,
132+
'userId': firebaseNotifier.user?.uid,
133+
}),
134+
headers: headers,
135+
);
136+
if (response.statusCode == 200) {
137+
print('Successfully verified purchase');
138+
return true;
139+
} else {
140+
print('failed request: ${response.statusCode} - ${response.body}');
141+
return false;
142+
}
133143
}
134144

135145
void _updateStreamOnDone() {
136146
_subscription.cancel();
137147
}
138148

139149
void _updateStreamOnError(dynamic error) {
140-
// ignore: avoid_print
141150
print(error);
142151
}
143152

0 commit comments

Comments
 (0)