From df8a38c31c7230c8b548b914aa6444274b5e12cf Mon Sep 17 00:00:00 2001 From: Guy Tepper Date: Sun, 5 Nov 2023 11:00:09 -0300 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20-=20Fix=20Android=20tip=20jar=20?= =?UTF-8?q?refunds=20(#341)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Tipping on Android were always refunded after a few days. The reason is that we didn't flush the purchase ("acknowledge" it to the play store): > your app must then acknowledge the purchase. This acknowledgement communicates to Google Play that you have granted entitlement for the purchase. We had the flushing mechanism set in the `TipJarScreen`, but putting it there will possibly hav the flushing effect not run (if the user has exit the screen before it ran, or for whatever reason else. Putting in the main `App` component will ensure it'll be flushed, either in the current session or in the next app relaunch. --- android/app/build.gradle | 2 +- app/app.tsx | 28 +++++++++++++++++-- .../settings/settings-tip-jar-screen.tsx | 16 ++--------- ios/BetterRail.xcodeproj/project.pbxproj | 20 ++++++------- ios/BetterRail/Info.plist | 2 +- ios/BetterRailWidget/Info.plist | 2 +- ios/StationIntent/Info.plist | 2 +- ios/WatchBetterRail Extension/Info.plist | 2 +- ios/WatchBetterRail/Info.plist | 2 +- 9 files changed, 44 insertions(+), 32 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index a2e1e1af..1f0a2086 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -120,7 +120,7 @@ android { applicationId "com.betterrail" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 75 + versionCode 78 versionName "2.2.2" missingDimensionStrategy "store", "play" } diff --git a/app/app.tsx b/app/app.tsx index 9b8cbb51..a3fda2d2 100644 --- a/app/app.tsx +++ b/app/app.tsx @@ -35,7 +35,7 @@ import { RootStore, RootStoreProvider, setupRootStore } from "./models" import { ToggleStorybook } from "../storybook/toggle-storybook" import { setInitialLanguage, setUserLanguage } from "./i18n/i18n" import "react-native-console-time-polyfill" -import { withIAPContext } from "react-native-iap" +import { useIAP, initConnection, finishTransaction, getAvailablePurchases, withIAPContext } from "react-native-iap" import PushNotification from "react-native-push-notification" // Disable tracking in development environment @@ -51,7 +51,6 @@ import { enableScreens } from "react-native-screens" import { canRunLiveActivities, monitorLiveActivities } from "./utils/ios-helpers" import { useDeepLinking } from "./hooks/use-deep-linking" import { openActiveRide } from "./utils/helpers/ride-helpers" -import { useStations } from "./data/stations" enableScreens() export const queryClient = new QueryClient() @@ -65,7 +64,7 @@ function App() { const [rootStore, setRootStore] = useState(undefined) const [localeReady, setLocaleReady] = useState(false) const appState = useRef(AppState.currentState) - const stations = useStations() + const { currentPurchase } = useIAP() useDeepLinking(rootStore, navigationRef) @@ -139,6 +138,29 @@ function App() { }) }, []) + useEffect(() => { + // load products and flush available purchases for the tip jar + // see: https://github.com/dooboolab-community/react-native-iap/issues/126 + // and: https://react-native-iap.dooboolab.com/docs/guides/purchases + const flushAvailablePurchases = async () => { + try { + await initConnection() + const availablePurchases = await getAvailablePurchases() + + availablePurchases.forEach((purchase) => { + finishTransaction({ purchase, isConsumable: true }) + }) + } catch (error) { + console.error("Failed to connect to IAP and finish all available transactions", error) + } + } + + // to avoid prompting for login during development, only flush purchases in production + if (!__DEV__) { + flushAvailablePurchases() + } + }, [currentPurchase]) + // Before we show the app, we have to wait for our state to be ready. // In the meantime, don't render anything. This will be the background // color set in native by rootView's background color. You can replace diff --git a/app/screens/settings/settings-tip-jar-screen.tsx b/app/screens/settings/settings-tip-jar-screen.tsx index a9b0bef3..dd5eb1a8 100644 --- a/app/screens/settings/settings-tip-jar-screen.tsx +++ b/app/screens/settings/settings-tip-jar-screen.tsx @@ -1,7 +1,7 @@ import React, { useEffect, useState } from "react" import { observer } from "mobx-react-lite" import { View, ViewStyle, TextStyle, Platform, ActivityIndicator } from "react-native" -import { ProductPurchase, Purchase, RequestPurchase, useIAP } from "react-native-iap" +import { ProductPurchase, RequestPurchase, useIAP } from "react-native-iap" import { Screen, Text } from "../../components" import { color, isDarkMode, spacing } from "../../theme" import { TouchableOpacity } from "react-native-gesture-handler" @@ -83,10 +83,10 @@ const TIP_AMOUNT: TextStyle = { const TOTAL_TIPS: TextStyle = { textAlign: "center", marginTop: spacing[4] } -const PRODUCT_IDS = ["better_rail_tip_1", "better_rail_tip_2", "better_rail_tip_3", "better_rail_tip_4"] - const installSource = getInstallerPackageNameSync() +const PRODUCT_IDS = ["better_rail_tip_1", "better_rail_tip_2", "better_rail_tip_3", "better_rail_tip_4"] + export const TipJarScreen = observer(function TipJarScreen() { const [isLoading, setIsLoading] = useState(false) const [thanksModalVisible, setModalVisible] = useState(false) @@ -97,18 +97,8 @@ export const TipJarScreen = observer(function TipJarScreen() { useIAP() useEffect(() => { - // see: https://github.com/dooboolab-community/react-native-iap/issues/126 - const flushAvailablePurchases = async () => { - await getAvailablePurchases() - availablePurchases.forEach(async (purchase) => { - await finishTransaction({ purchase, isConsumable: true }) - }) - } - if (connected) { getProducts({ skus: PRODUCT_IDS }) - - flushAvailablePurchases() } }, [connected, getProducts]) diff --git a/ios/BetterRail.xcodeproj/project.pbxproj b/ios/BetterRail.xcodeproj/project.pbxproj index 9365ce60..4df30f46 100644 --- a/ios/BetterRail.xcodeproj/project.pbxproj +++ b/ios/BetterRail.xcodeproj/project.pbxproj @@ -1156,7 +1156,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = BetterRail/BetterRailDebug.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UE6BVYPPFX; ENABLE_BITCODE = NO; @@ -1196,7 +1196,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UE6BVYPPFX; INFOPLIST_FILE = BetterRail/Info.plist; @@ -1359,7 +1359,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=watchos*]" = UE6BVYPPFX; @@ -1401,7 +1401,7 @@ "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=watchos*]" = UE6BVYPPFX; @@ -1437,7 +1437,7 @@ CODE_SIGN_ENTITLEMENTS = "WatchBetterRail Extension/WatchBetterRail Extension.entitlements"; "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=watchos*]" = UE6BVYPPFX; @@ -1478,7 +1478,7 @@ "CODE_SIGN_IDENTITY[sdk=watchos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=watchos*]" = UE6BVYPPFX; @@ -1516,7 +1516,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = BetterRailWidgetExtensionDebug.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UE6BVYPPFX; @@ -1557,7 +1557,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UE6BVYPPFX; @@ -1590,7 +1590,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = StationIntent/StationIntentDebug.entitlements; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UE6BVYPPFX; @@ -1629,7 +1629,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 3; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = UE6BVYPPFX; diff --git a/ios/BetterRail/Info.plist b/ios/BetterRail/Info.plist index d92d919d..2d8daff4 100644 --- a/ios/BetterRail/Info.plist +++ b/ios/BetterRail/Info.plist @@ -23,7 +23,7 @@ CFBundleSignature ???? CFBundleVersion - 1 + 3 ITSAppUsesNonExemptEncryption LSApplicationQueriesSchemes diff --git a/ios/BetterRailWidget/Info.plist b/ios/BetterRailWidget/Info.plist index 3c6e38da..2dc31726 100644 --- a/ios/BetterRailWidget/Info.plist +++ b/ios/BetterRailWidget/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - $(CURRENT_PROJECT_VERSION) + 3 NSExtension NSExtensionPointIdentifier diff --git a/ios/StationIntent/Info.plist b/ios/StationIntent/Info.plist index 0bc7d1fc..8531d803 100644 --- a/ios/StationIntent/Info.plist +++ b/ios/StationIntent/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - $(CURRENT_PROJECT_VERSION) + 3 NSExtension NSExtensionAttributes diff --git a/ios/WatchBetterRail Extension/Info.plist b/ios/WatchBetterRail Extension/Info.plist index 03ad0db8..e688a98d 100644 --- a/ios/WatchBetterRail Extension/Info.plist +++ b/ios/WatchBetterRail Extension/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - $(CURRENT_PROJECT_VERSION) + 3 CLKComplicationPrincipalClass $(PRODUCT_MODULE_NAME).ComplicationController NSExtension diff --git a/ios/WatchBetterRail/Info.plist b/ios/WatchBetterRail/Info.plist index 9a07f13d..d053b690 100644 --- a/ios/WatchBetterRail/Info.plist +++ b/ios/WatchBetterRail/Info.plist @@ -19,7 +19,7 @@ CFBundleShortVersionString $(MARKETING_VERSION) CFBundleVersion - $(CURRENT_PROJECT_VERSION) + 3 UISupportedInterfaceOrientations UIInterfaceOrientationPortrait