reason

增加支付

......@@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 31
compileSdkVersion 32
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
......@@ -51,7 +51,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "pub.yiyan.parlando.Parlando"
minSdkVersion 21
targetSdkVersion 31
targetSdkVersion 32
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
......
......@@ -2,6 +2,8 @@
xmlns:tools="http://schemas.android.com/tools"
package="pub.yiyan.parlando.Parlando">
<uses-permission android:name="com.android.vending.BILLING" />
<application
android:requestLegacyExternalStorage="true"
tools:replace="android:label"
......@@ -47,8 +49,5 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<meta-data
android:name="com.google.android.gms.wallet.api.enabled"
android:value="true" />
</application>
</manifest>
......
org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
android.bundle.enableUncompressedNativeLibs=false
\ No newline at end of file
......
......@@ -23,7 +23,6 @@ import 'util/device_utils.dart';
import 'util/handle_error_utils.dart';
import 'util/log_utils.dart';
import 'util/theme_utils.dart';
///
/// 配置本地化的方法
/// 1. 安裝Flutter intl插件
......@@ -96,7 +95,7 @@ class MyApp extends StatelessWidget {
}
interceptors.add(AdapterInterceptor());
configDio(
baseUrl: 'http://www.yiyan.pub/api/v1/',
baseUrl: 'https://www.yiyan.pub/api/v1/',
interceptors: interceptors,
);
}
......
import 'dart:async';
import 'dart:io';
import 'dart:ui';
import 'package:Parlando/apis/api_response.dart';
import 'package:Parlando/login/login_router.dart';
import 'package:Parlando/membership/models/membership_entity.dart';
import 'package:Parlando/membership/models/order_entity.dart';
import 'package:Parlando/membership/models/pay_entity.dart';
import 'package:Parlando/membership/view_models/membership_view_model.dart';
import 'package:Parlando/net/dio_utils.dart';
import 'package:Parlando/net/http_api.dart';
import 'package:Parlando/res/constant.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flustars/flustars.dart';
......@@ -15,8 +13,7 @@ import 'package:flutter/material.dart';
import 'package:Parlando/res/resources.dart';
import 'package:Parlando/routers/fluro_navigator.dart';
import 'package:Parlando/extension/int_extension.dart';
import 'package:Parlando/util/toast_utils.dart';
import 'package:flutter_braintree/flutter_braintree.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
import 'package:provider/provider.dart';
class MembershipPage extends StatefulWidget {
......@@ -30,6 +27,19 @@ class MembershipPageState extends State<MembershipPage>
with WidgetsBindingObserver {
bool _isLoading = false;
late StreamSubscription _purchaseUpdatedSubscription;
late StreamSubscription _purchaseErrorSubscription;
late StreamSubscription _conectionSubscription;
final List<String> _productLists = Platform.isAndroid
? [
'test.yiyan.vip.1.month',
]
: ['test.yiyan.vip.1.month'];
String _platformVersion = 'Unknown';
List<IAPItem> _items = [];
List<PurchasedItem> _purchases = [];
@override
void initState() {
super.initState();
......@@ -38,6 +48,8 @@ class MembershipPageState extends State<MembershipPage>
.setSelectedMembership(null);
Provider.of<MembershipViewProvider>(context, listen: false)
.fetchMembershipData('0');
initPlatformState();
} else {
NavigatorUtils.push(context, LoginRouter.loginPage, replace: true);
}
......@@ -115,13 +127,11 @@ class MembershipPageState extends State<MembershipPage>
),
Gaps.vGap24,
// TODO 如果会员则显示会员详情
Expanded(
child: ListView.builder(
itemExtent: 48.0,
itemBuilder: (_, index) {
return _buildItem(mb.goodsList![index]);
},
itemCount: mb.goodsList!.length,
SizedBox(
width: double.infinity,
height: 100,
child: Column(
children: _renderInApps(),
),
),
Gaps.vGap24,
......@@ -135,7 +145,7 @@ class MembershipPageState extends State<MembershipPage>
Gaps.vGap10,
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
......@@ -205,95 +215,77 @@ class MembershipPageState extends State<MembershipPage>
}
}
Widget _buildItem(MembershipDataGoodsList goods) {
return Flex(
direction: Axis.horizontal,
children: [
Text(
goods.name!,
style: const TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
Gaps.hGap10,
Expanded(
flex: 1,
child: Align(
alignment: Alignment.centerRight,
child: Text(
goods.price!,
style: const TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
),
),
Gaps.hGap32,
ElevatedButton(
child: const Text(
"开通",
style: TextStyle(color: Colors.white, fontSize: 15.0),
),
onPressed: () {
DioUtils.instance.requestNetwork<OrderEntity>(
Method.post,
HttpApi.order,
params: {'goods_id': goods.id},
onSuccess: (data) {
String orderSn = data!.data!.orderSn!;
DioUtils.instance.requestNetwork<PayEntity>(
Method.get,
"${HttpApi.pay}?order_sn=$orderSn&pay_type=paypal",
params: [],
onSuccess: (data) {
String id = data!.data!.id!;
payPalRequest(id);
_isLoading = false;
},
onError: (code, msg) {
Toast.show(msg.toString());
_isLoading = false;
setState(() {});
},
);
_isLoading = false;
},
onError: (code, msg) {
Toast.show(msg.toString());
_isLoading = false;
setState(() {});
},
);
},
),
],
);
}
Future<void> payPalRequest(String key) async {
final request = BraintreePayPalRequest(
amount: '0.01',
currencyCode: 'CNY',
billingAgreementDescription: '贝宝支付很无敌',
);
BraintreePaymentMethodNonce? result = await Braintree.requestPaypalNonce(
key,
request,
);
if (result != null) {
print('Nonce: ${result.nonce}');
} else {
print('PayPal flow was canceled.');
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {}
@override
void dispose() {
_conectionSubscription.cancel();
super.dispose();
}
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
// prepare
var result = await FlutterInappPurchase.instance.initialize();
print('result: $result');
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
// _platformVersion = platformVersion;
});
// refresh items for android
try {
String msg = await FlutterInappPurchase.instance.consumeAll();
print('consumeAllItems: $msg');
} catch (err) {
print('consumeAllItems error: $err');
}
_conectionSubscription =
FlutterInappPurchase.connectionUpdated.listen((connected) {
print('connected: $connected');
});
_purchaseUpdatedSubscription =
FlutterInappPurchase.purchaseUpdated.listen((productItem) {
print('purchase-updated: $productItem');
});
_purchaseErrorSubscription =
FlutterInappPurchase.purchaseError.listen((purchaseError) {
print('purchase-error: $purchaseError');
});
List<IAPItem> items =
await FlutterInappPurchase.instance.getSubscriptions(_productLists);
for (var item in items) {
print('${item.toString()}');
_items.add(item);
}
setState(() {
_items = items;
_purchases = [];
});
}
List<Widget> _renderInApps() {
List<Widget> widgets = <Widget>[];
for (IAPItem item in _items) {
widgets.add(Text(item.title!));
}
return widgets;
}
void _requestPurchase(IAPItem item) {
FlutterInappPurchase.instance.requestPurchase(item.productId!);
}
}
......
This diff is collapsed. Click to expand it.
......@@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1
version: 1.0.0+2
environment:
sdk: ">=2.16.2 <3.0.0"
......@@ -113,7 +113,7 @@ dependencies:
animated_radial_menu: ^0.0.1
flutter_braintree: ^2.3.1
flutter_inapp_purchase: ^5.3.0
dependency_overrides:
decimal: 1.5.0
......