Skip to content

Commit

Permalink
Fixed iOS IAP. (#962)
Browse files Browse the repository at this point in the history
* Update flashlight and go versions (#949)

* Update flashlight and go versions

* Do not enforce go version in Makefile

* Revert "Update flashlight and go versions (#949)" (#950)

This reverts commit eab0e69.

* add a template for GitHub integrated release notes

* generate automatic changelog on release, then trigger automation repo

* fixed IAP flow

* fixed IAP flow

---------

Co-authored-by: Myles Horton <[email protected]>
Co-authored-by: atavism <[email protected]>
Co-authored-by: Jay <[email protected]>
  • Loading branch information
4 people authored Dec 12, 2023
1 parent a41db28 commit ccf76da
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 35 deletions.
27 changes: 27 additions & 0 deletions .github/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# template for auto-generated release notes
# https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes

changelog:
# exclude:
# labels:
# - ignore-for-release
# authors:
# - octocat
categories:
- title: ✨ Major Features
labels:
- epic
- title: 🪲 Bug Fixes
labels:
- bug
- cs
- title: 📱 Team Apps
labels:
- team_apps
- title: 📶 Team SDK
labels:
- team_sdk
- title: 🛠️ Team Infra
labels:
- team_infra
- telemetry
42 changes: 42 additions & 0 deletions .github/workflows/release-changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Release and Changelog

on:
workflow_dispatch:
push:
tags:
# a prerelease noted by a hyphen will not trigger
- 'lantern-[0-9]+.[0-9]+.[0-9]+'

jobs:
create-release:
runs-on: ubuntu-latest
steps:
- name: Create release
env:
GH_TOKEN: ${{ github.token }}
# https://docs.github.com/en/rest/releases/releases?apiVersion=2022-11-28#create-a-release
run: |
gh api -i \
--method POST \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
/repos/${{ github.repository }}/releases \
-f tag_name='${{ github.ref_name }}' \
-f name='Release ${{ github.ref_name }}' \
-f body='🤖 Autogenerated changelog for ${{ github.repository }} ${{ github.ref_name }}' \
-F draft=false \
-F prerelease=false \
-F generate_release_notes=true
- name: Strip repository name of owner
id: repo
run: |
echo "REPO_NAME=$(echo ${{ github.repository }} | sed s/'${{ github.repository_owner }}\/'//g)" >> "$GITHUB_OUTPUT"
- name: Trigger QC Checklist in customer-service repo
env:
GH_GRANTS_TOKEN: ${{ secrets.GH_GRANTS_TOKEN }}
run: |
echo "Sending QC Checklist trigger for ${{ steps.repo.outputs.REPO_NAME }} ${{ github.ref_name }}"
curl -i -H "Accept: application/vnd.github.everest-preview+json" \
-H "Authorization: token $GH_GRANTS_TOKEN" \
--request POST --data '{"event_type": "TRIGGER_QC_CHECKLIST", "client_payload": { "platform": "${{ steps.repo.outputs.REPO_NAME }}", "version": "${{ github.ref_name }}"}}' \
https://api.github.com/repos/getlantern/customer-support/dispatches
12 changes: 8 additions & 4 deletions internalsdk/session_model.go
Original file line number Diff line number Diff line change
Expand Up @@ -843,7 +843,7 @@ func redeemResellerCode(m *SessionModel, email string, resellerCode string) erro
return err
}

err, purchaseData := createPurchaseData(m, paymentProviderResellerCode, resellerCode, "")
err, purchaseData := createPurchaseData(m, paymentProviderResellerCode, resellerCode, "", "")
if err != nil {
log.Errorf("Error while creating purchase data %v", err)
return err
Expand Down Expand Up @@ -874,12 +874,13 @@ func redeemResellerCode(m *SessionModel, email string, resellerCode string) erro
}

func submitApplePayPayment(m *SessionModel, planId string, purchaseToken string) error {
err, purchaseData := createPurchaseData(m, paymentProviderApplePay, "", purchaseToken)
log.Errorf("Submit Apple Pay Payment planId %v purchaseToken %v", planId, purchaseToken)
err, purchaseData := createPurchaseData(m, paymentProviderApplePay, "", purchaseToken, planId)
if err != nil {
log.Errorf("Error while creating purchase data %v", err)
return err
}

log.Errorf("Purchase data %v", purchaseData)
deviecId, err := m.GetDeviceID()
if err != nil {
return err
Expand All @@ -898,8 +899,11 @@ func submitApplePayPayment(m *SessionModel, planId string, purchaseToken string)
if err != nil {
return err
}
log.Debugf("Purchase Request response %v", purchase)
log.Errorf("Purchase Request response %+v", purchase)

if purchase.Status != "ok" {
return errors.New("Purchase Request failed")
}
// Set user to pro
return setProUser(m.baseModel, true)
}
6 changes: 3 additions & 3 deletions internalsdk/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func formatRenewalBonusExpected(months int64, days int64, longForm bool) string

//Create Purchase Request

func createPurchaseData(session *SessionModel, paymentProvider string, resellerCode string, purchaseToken string) (error, map[string]string) {
func createPurchaseData(session *SessionModel, paymentProvider string, resellerCode string, purchaseToken string, planId string) (error, map[string]string) {
email, err := session.Email()
if err != nil {
return err, nil
Expand All @@ -126,11 +126,11 @@ func createPurchaseData(session *SessionModel, paymentProvider string, resellerC
data["provider"] = paymentProviderResellerCode
data["resellerCode"] = resellerCode
data["currency"] = "usd"
data["plan"] = ""
data["plan"] = planId
case paymentProviderApplePay:
data["token"] = purchaseToken
data["currency"] = "usd"
data["plan"] = ""
data["plan"] = planId

}

Expand Down
4 changes: 2 additions & 2 deletions lib/common/session_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -393,12 +393,12 @@ class SessionModel extends Model {
}).then((value) => value as String);
}

Future<void> submitApplePlay(String planID,String purchaseToken) async {
Future<void> submitApplePlay(String planID, String purchaseToken) async {
return methodChannel
.invokeMethod('submitApplePayPayment', <String, dynamic>{
'planID': planID,
'purchaseId': purchaseToken,
}).then((value) => value as String);
});
}

Future<void> submitStripePayment(
Expand Down
61 changes: 35 additions & 26 deletions lib/core/purchase/app_purchase.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ class AppPurchase {
String _planId = "";

void init() {
getAvailablePlans();
final purchaseUpdated = _inAppPurchase.purchaseStream;
_subscription = purchaseUpdated.listen(
_onPurchaseUpdate,
onDone: _updateStreamOnDone,
onError: _updateStreamOnError,
);
getAvailablePlans();
}

Future<void> getAvailablePlans() async {
Expand All @@ -29,15 +29,22 @@ class AppPurchase {
plansSku.addAll(response.productDetails);
}

void startPurchase(String planId,
{required VoidCallback onSuccess,
required Function(dynamic error) onFailure}) {
Future<void> startPurchase(
String planId, {
required VoidCallback onSuccess,
required Function(dynamic error) onFailure,
}) async {
_planId = planId;
_onSuccess = onSuccess;
_onError = onFailure;
final plan = _normalizePlan(planId);
final purchaseParam = PurchaseParam(productDetails: plan);
_inAppPurchase.buyConsumable(purchaseParam: purchaseParam);
try {
await _inAppPurchase.buyConsumable(purchaseParam: purchaseParam);
} on PlatformException catch (e) {
logger.e('Error while calling purchase api', error: e);
Sentry.captureException(e);
}
}

ProductDetails _normalizePlan(String planId) {
Expand All @@ -47,31 +54,33 @@ class AppPurchase {
/// So we split and compare with lowercase
final newPlanId = planId.split('-')[0];
return plansSku.firstWhere(
(element) => element.id.toLowerCase() == newPlanId.toLowerCase());
(element) => element.id.toLowerCase() == newPlanId.toLowerCase(),
);
}

// Internal methods
Future<void> _onPurchaseUpdate(
List<PurchaseDetails> purchaseDetailsList) async {
print("purchase length ${purchaseDetailsList.length}");
final purchase = purchaseDetailsList[0];
// // Handle purchases here
// for (final purchase in purchaseDetailsList) {
// print("purchase $purchase");
// }

logger.i('Calling Purchase API');
try {
sessionModel.submitApplePlay(_planId, purchase.purchaseID!);
List<PurchaseDetails> purchaseDetailsList,
) async {
for (var purchaseDetails in purchaseDetailsList) {
await _handlePurchase(purchaseDetails);
}
}

//Check if purchase is sill in pending state complete purchase
if (purchase.pendingCompletePurchase) {
await _inAppPurchase.completePurchase(purchase);
Future<void> _handlePurchase(PurchaseDetails purchaseDetails) async {
if (purchaseDetails.status == PurchaseStatus.purchased) {
try {
await sessionModel.submitApplePlay(
_planId,
purchaseDetails.verificationData.serverVerificationData,
);
_onSuccess?.call();
} catch (e) {
logger.e("purchase error", error: e);
Sentry.captureException(e);
}
_onSuccess?.call();
} catch (e) {
logger.e('Error while calling purchase api', error: e);
Sentry.captureException(e);
}
if (purchaseDetails.pendingCompletePurchase) {
await _inAppPurchase.completePurchase(purchaseDetails);
}
}

Expand All @@ -84,7 +93,7 @@ class AppPurchase {

void _updateStreamOnError(dynamic error) {
//Handle error here
print("purchase error $error");
logger.e("purchase error", error: error);
if (_onError != null) {
_onError?.call(error);
}
Expand Down
2 changes: 2 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import device_info_plus
import emoji_picker_flutter
import flutter_inappwebview
import flutter_local_notifications
import in_app_purchase_storekit
import package_info_plus
import path_provider_foundation
import sentry_flutter
Expand All @@ -25,6 +26,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
EmojiPickerFlutterPlugin.register(with: registry.registrar(forPlugin: "EmojiPickerFlutterPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin"))
InAppPurchasePlugin.register(with: registry.registrar(forPlugin: "InAppPurchasePlugin"))
FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SentryFlutterPlugin.register(with: registry.registrar(forPlugin: "SentryFlutterPlugin"))
Expand Down

0 comments on commit ccf76da

Please sign in to comment.