از Appwrite و Flutter برای ایجاد یک سرویس کیف پول موبایل بدون سرور استفاده کنید

کیف پول های موبایل، کیف پول های مجازی/دیجیتالی هستند که اطلاعات کارت های وفاداری، کوپن ها، کارت های اعتباری و کارت های نقدی را در گوشی های هوشمند یا تبلت ذخیره می کنند. آنها یک روش راحت را برای کاربران برای پرداخت آنلاین و در فروشگاه ارائه می دهند.
در این پست، نحوه استفاده از ویژگی های پایگاه داده Appwrite را برای ساخت قابلیت کیف پول موبایل در اپلیکیشن فلاتر یاد خواهیم گرفت. مخزن GitHub پروژه را می توانید در اینجا بیابید.
پیش نیازها
برای درک کامل مفاهیم ارائه شده در این آموزش، موارد زیر مورد نیاز است:
شروع شدن
برای شروع، باید پروژه را با رفتن به دایرکتوری مورد نظر و اجرای دستور زیر کلون کنیم:
git clone https://github.com/Mr-Malomz/mobile_wallet.git
اجرای پروژه
ابتدا باید وابستگی های پروژه را با اجرای دستور زیر نصب کنیم:
flutter pub get
سپس با استفاده از دستور زیر پروژه را اجرا کنید:
flutter run
دستور بالا برنامه را در دستگاه انتخاب شده اجرا می کند.
سرویس کیف پول موبایل را در Appwrite راه اندازی کنید
برای شروع، باید وارد کنسول Appwrite خود شویم، روی آن کلیک کنید پروژه ایجاد کنید دکمه، ورودی mobile_wallet
به عنوان نام، و سپس کلیک کنید ايجاد كردن.
یک پایگاه داده، مجموعه، ویژگی ها و داده های نمونه ایجاد کنید
با ایجاد پروژه ما، می توانیم پایگاه داده برنامه خود را راه اندازی کنیم. ابتدا به مسیر بروید پایگاه داده برگه را کلیک کنید ایجاد پایگاه داده دکمه، ورودی wallet
به عنوان نام، و سپس کلیک کنید ايجاد كردن.
دوم اینکه باید دو مجموعه برای ذخیره سازی ایجاد کنیم کاربر جزئیات و معاملات بر روی کیف پول انجام می شود. برای انجام این کار، روی مجموعه ایجاد کنید دکمه، ورودی users
به عنوان نام، و سپس کلیک کنید ايجاد كردن. با پیروی از همین رویکرد، باید a ایجاد کنیم transactions
مجموعه.
ثالثاً، ما نیاز به ایجاد ویژگی هایی برای نمایش فیلدهای پایگاه داده خود داریم. برای انجام این کار، باید به مسیر بروید ویژگی های برگه را بزنید و برای هر یک از مجموعه ها، مانند شکل زیر، ویژگی ایجاد کنید:
برای users
مجموعه:
کلید ویژگی | نوع صفت | اندازه | ضروری |
---|---|---|---|
نام | رشته | 250 | آره |
تعادل | عدد صحیح | 5000 | آره |
ما همچنین باید مجوز مجموعه خود را به روز کنیم تا آنها را بر اساس آن مدیریت کنیم. برای انجام این کار، باید به مسیر بروید تنظیمات برگه، به به روز رسانی مجوزها بخش، انتخاب کنید Any
را علامت بزنید و سپس کلیک کنید به روز رسانی.
برای transactions
مجموعه:
کلید ویژگی | نوع صفت | اندازه | ضروری |
---|---|---|---|
شناسه کاربر | رشته | 250 | آره |
نام | رشته | 250 | آره |
روش پرداخت | رشته | 250 | آره |
میزان | عدد صحیح | 5000 | آره |
با دنبال کردن همان مراحل بالا، ما همچنین باید مجوز مجموعه را به روز کنیم و به روز کنیم.
در نهایت، ما باید داده های نمونه را برای شبیه سازی داده های کیف پول خود اضافه کنیم. برای انجام این کار، باید به مسیر بروید سند برگه را کلیک کنید سند ایجاد کنید را فشار دهید و داده ها را برای هر یک از مجموعه ها مانند شکل زیر اضافه کنید:
برای users
سند:
نام | تعادل |
---|---|
جان تراولتا | 1200 |
هنگام ایجاد سند، باید شناسه سند را نیز کپی کنیم، زیرا هنگام ایجاد تراکنش ها به عنوان مرجعی برای کاربر عمل می کند.
برای transactions
سند:
شناسه کاربر | نام | روش پرداخت | میزان |
---|---|---|---|
شناسه کاربری کپی شده | مواد غذایی | پرداخت اینترنتی | 10 |
شناسه کاربری کپی شده | اشتراک تماس بگیرید | NFT | 15 |
یک فهرست به مجموعه تراکنش ها اضافه کنید
پایگاه های داده از شاخص ها برای بهبود سرعت بازیابی داده ها استفاده می کنند. برای اضافه کردن یک شاخص به transactions
مجموعه، به شاخص ها برگه، کلیک کنید ایجاد نمایه دکمه، ورودی userId
به عنوان کلید فهرست، را انتخاب کنید userId
به عنوان صفت و DESC
به عنوان سفارش، و سپس کلیک کنید ايجاد كردن.
پشتیبانی پلت فرم را اضافه کنید
برای افزودن پشتیبانی از برنامه Flutter ما، به این قسمت بروید صفحه اصلی منو و کلیک کنید اپلیکیشن فلاتر دکمه.
بسته به دستگاهی که برای اجرای برنامه Flutter استفاده می شود، می توانیم آن را مطابق شکل زیر تغییر دهیم.
iOS
برای بدست آوردن Bundle ID، میتوانیم از مسیر زیر استفاده کنیم:
ios > Runner.xcodeproj > project.pbxproj
باز کن project.pbxproj
فایل و جستجو کنید PRODUCT_BUNDLE_IDENTIFIER
.
بعد، دایرکتوری پروژه را در Xcode باز کنید، آن را باز کنید Runner.xcworkspace
پوشه موجود در پوشه iOS برنامه، را انتخاب کنید دونده پروژه را در ناوبر پروژه Xcode انتخاب کنید دونده در نوار کناری منوی اصلی هدف قرار دهید و سپس انتخاب کنید منسیستم عامل 11 در هدف اطلاعات استقرار
اندروید
برای دریافت نام بسته خود، می توانیم با استفاده از مسیر زیر به یک فایل XML برویم:
android > app > src > debug > AndroidManifest.xml
باز کن AndroidManifest.xml
فایل و کپی کنید package
ارزش.
بعد، ما باید آن را اصلاح کنیم AndroidManifext.xml
همانطور که در زیر نشان داده شده است:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.mobile_wallet">
<uses-permission android:name="android.permission.INTERNET"/>
<application ...>
<activity android:name="com.linusu.mobile_wallet.CallbackActivity" android:exported="true">
<intent-filter android:label="mobile_wallet">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="appwrite-callback-[PROJECT_ID]" />
</intent-filter>
</activity>
</application>
</manifest>
ما همچنین باید برجسته شده را جایگزین کنیم [PROJECT_ID]
با شناسه واقعی پروژه Appwrite ما.
ساخت سرویس کیف پول موبایل
با تمام کارهای انجام شده، بیایید سرویس کیف پول موبایل را بسازیم. ابتدا باید مدل هایی ایجاد کنیم تا پاسخ ارسال شده از Appwrite را به یک شی Dart تبدیل کنیم. این مدل ها همچنین به سریال سازی JSON نیز پاسخ خواهند داد. برای این کار باید a ایجاد کنیم utils.dart
فایل در lib
پوشه را وارد کنید و قطعه زیر را اضافه کنید:
class AppConstant {
final String databaseId = "REPLACE WITH DATABASE ID";
final String projectId = "REPLACE WITH PROJECT ID";
final String userCollectionId = "REPLACE WITH USERS COLLECTION ID";
final String transactionCollectionId = "REPLACE WITH TRANSACTIONS COLLECTION ID";
final String userId = "REPLACE WITH SAMPLE ID";
final String endpoint = "ENDPOINT";
}
class User {
String? $id;
String name;
int balance;
User({this.$id, required this.name, required this.balance});
Map<dynamic, dynamic> toJson() {
return {"name": name, "balance": balance};
}
factory User.fromJson(Map<dynamic, dynamic> json) {
return User(
$id: json['\$id'], name: json['name'], balance: json['balance']);
}
}
class Transaction {
String? $id;
String userId;
String name;
String paymentMethod;
int amount;
Transaction({
this.$id,
required this.userId,
required this.name,
required this.paymentMethod,
required this.amount,
});
Map<dynamic, dynamic> toJson() {
return {
"userId": userId,
"name": name,
"paymentMethod": paymentMethod,
"amount": amount
};
}
factory Transaction.fromJson(Map<dynamic, dynamic> json) {
return Transaction(
userId: json['userId'],
name: json['name'],
paymentMethod: json['paymentMethod'],
amount: json['amount']);
}
}
ما باید آن را اصلاح کنیم endpoint
ویژگی تا بتواند با آدرس شبکه محلی سیستم ما کار کند. ما می توانیم بر این اساس تنظیم کنیم:
iOS
حرکت به شبکه بخش و آدرس IP را کپی کنید.
اندروید
ما می توانیم شبیه ساز اندروید خود را با استفاده از آی پی سیستم وصل کنیم 10.0.2.2
آدرس آی پی.
final String endpoint = "http://10.0.2.2/v1";
توجه داشته باشید: ما می توانیم دریافت کنیم databaseId
، projectId
، collectionId
اس، functionId
، و userId
با پیمایش از طریق کنسول Appwrite.
در مرحله بعد، ما باید یک فایل سرویس ایجاد کنیم تا منطق هسته برنامه را از UI جدا کنیم. برای انجام این کار، یک را ایجاد کنید wallet_service.dart
فایل داخل lib
فهرست راهنما. سپس قطعه زیر را اضافه کنید:
import 'package:appwrite/appwrite.dart';
import 'package:mobile_wallet/utils.dart';
class WalletService {
Client _client = Client();
Databases? _db;
WalletService() {
_init();
}
//initialize the application
_init() async {
_client
.setEndpoint(AppConstant().endpoint)
.setProject(AppConstant().projectId);
_db = Databases(_client);
//get current session
Account account = Account(_client);
try {
await account.get();
} on AppwriteException catch (e) {
if (e.code == 401) {
account
.createAnonymousSession()
.then((value) => value)
.catchError((e) => e);
}
}
}
}
قطعه بالا کارهای زیر را انجام می دهد:
- وابستگی های مورد نیاز را وارد می کند
- a را ایجاد می کند
WalletService
کلاس با_client
،_db
خواص برای اتصال به نمونه Appwrite و پایگاه داده - یک را ایجاد می کند
_init
روشی که Appwrite را با استفاده از ویژگی ها پیکربندی می کند و همچنین به صورت مشروط یک کاربر ناشناس برای دسترسی به پایگاه داده Appwrite ایجاد می کند.
در نهایت، ما باید آن را اصلاح کنیم WalletService
کلاس با اضافه کردن getUserDetails
، updateUserBalance
، createTransaction
، و getTransactions
روش هایی که از _db
دارایی برای مدیریت عملیات کیف پول بر این اساس.
//imports go here
class WalletService {
Client _client = Client();
Databases? _db;
WalletService() {
_init();
}
//initialize the application
_init() async {
//init code goes here
}
Future<User> getUserDetails() async {
try {
var data = await _db?.getDocument(
databaseId: AppConstant().databaseId,
collectionId: AppConstant().userCollectionId,
documentId: AppConstant().userId);
var user = data?.convertTo((doc) => User.fromJson(doc));
return user!;
} catch (e) {
throw Exception('Error getting user details');
}
}
Future updateUserBalance(
String userId,
String name,
int balance,
int amount,
) async {
int newBalance = balance - amount;
try {
User updatedUserBalance = User(name: name, balance: newBalance);
var result = await _db?.updateDocument(
databaseId: AppConstant().databaseId,
collectionId: AppConstant().userCollectionId,
documentId: userId,
data: updatedUserBalance.toJson());
return result;
} catch (e) {
throw Exception('Error updating user balance!');
}
}
Future createTransaction(String userId, int amount) async {
try {
Transaction updatedTransaction = Transaction(
userId: userId,
name: "Stamp duty",
paymentMethod: "internet payment",
amount: amount,
);
var data = await _db?.createDocument(
databaseId: AppConstant().databaseId,
collectionId: AppConstant().transactionCollectionId,
documentId: ID.unique(),
data: updatedTransaction.toJson(),
);
return data;
} catch (e) {
throw Exception('Error creating transaction!');
}
}
Future<List<Transaction>> getTransactions() async {
try {
var data = await _db?.listDocuments(
databaseId: AppConstant().databaseId,
collectionId: AppConstant().transactionCollectionId,
queries: [Query.orderDesc('userId')],
);
var transactionList = data?.documents
.map((transaction) => Transaction.fromJson(transaction.data))
.toList();
return transactionList!;
} catch (e) {
throw Exception('Error getting list of transactions!');
}
}
}
PS: در createTransaction
روش، ما جزئیات تراکنش هارد کد را برای اهداف شبیه سازی کردیم.
مصرف سرویس
با انجام این کار، می توانیم شروع به استفاده از سرویس برای انجام عملیات مورد نیاز کنیم.
اطلاعات کاربران را دریافت کنید و یک تراکنش ایجاد کنید
برای شروع، باید آن را اصلاح کنیم home.dart
فایل در screens
دایرکتوری و با انجام موارد زیر آن را به روز کنید:
ابتدا باید وابستگی های مورد نیاز را وارد کنیم و روش هایی را برای دریافت جزئیات کاربر و ایجاد تراکنش ایجاد کنیم:
import 'package:flutter/material.dart';
import 'package:mobile_wallet/screens/transactions.dart';
import 'package:mobile_wallet/utils.dart';
import 'package:mobile_wallet/wallet_service.dart';
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
late User user;
bool _isLoading = false;
bool _isTransacting = false;
bool _isError = false;
@override
void initState() {
_getUserDetails();
super.initState();
}
_getUserDetails() {
setState(() {
_isLoading = true;
});
WalletService().getUserDetails().then((value) {
setState(() {
user = value;
_isLoading = false;
});
}).catchError((e) {
setState(() {
_isLoading = false;
_isError = true;
});
});
}
_createTransaction(String userId, String name, int balance) {
setState(() {
_isTransacting = true;
});
int amount = 20;
WalletService().createTransaction(userId, amount).then((value) {
WalletService()
.updateUserBalance(userId, name, balance, amount)
.then((value) {
//update balance in app
int newBalance = user.balance - amount;
setState(() {
_isTransacting = false;
user.balance = newBalance;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Transaction created successfully!')),
);
}).catchError((e) {
setState(() {
_isTransacting = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Error creating transaction!')),
);
});
}).catchError((e) {
setState(() {
_isTransacting = false;
});
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Error creating transaction!')),
);
});
}
@override
Widget build(BuildContext context) {
//UI code goes here
}
}
قطعه بالا کارهای زیر را انجام می دهد:
- خطوط 1-4: وابستگی های مورد نیاز را وارد کنید
-
خط 13-16: ایجاد کنید
user
،_isLoading
،_isTransacting
، و_isError
خواص برای مدیریت وضعیت برنامه -
خطوط 18-39: ایجاد یک
_getUserDetails
روشی برای به دست آوردن جزئیات کاربر با استفاده ازWalletService().getUserDetails
سرویس، وضعیت ها را بر اساس آن تنظیم کنید و از آن استفاده کنیدinitState
روش فراخوانی_getUserDetails
-
خطوط 41-75: ایجاد یک
_createTransaction
روشی برای شبیه سازی تراکنش با استفاده ازWalletService().createTransaction
خدمات، و در ایجاد موفقیت آمیز، استفاده می کندWalletService().updateUserBalance
خدمات به روز رسانی موجودی کیف پول
در نهایت، ما باید UI را تغییر دهیم تا به صورت مشروط جزئیات کاربران را نشان دهیم و یک تراکنش را با استفاده از روشها و حالتهای ایجاد شده در بالا شبیهسازی کنیم.
//import goes here
class Home extends StatefulWidget {
//code goes here
}
class _HomeState extends State<Home> {
//states goes here
@override
void initState() {
_getUserDetails();
super.initState();
}
_getUserDetails() {
//code goes here
}
_createTransaction(String userId, String name, int balance) {
//code goes here
}
@override
Widget build(BuildContext context) {
return _isLoading
? const Center(
child: CircularProgressIndicator(
color: Colors.blue,
))
: _isError
? const Center(
child: Text(
'Error getting users details',
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
)
: Scaffold(
backgroundColor: Colors.white,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset('images/wallet.jpg'),
const SizedBox(height: 40.0),
const Text(
'WALLET BALANCE',
style: TextStyle(
fontSize: 12.0, fontWeight: FontWeight.w500),
),
const SizedBox(height: 5.0),
Text(
'\$ ${user.balance}',
style: TextStyle(
fontSize: 32.0, fontWeight: FontWeight.bold),
),
const SizedBox(height: 40.0),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
OutlinedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
const Transactions()),
);
},
child: Text(
'View transactions',
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
color: Colors.black),
),
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0),
),
),
side: MaterialStateProperty.all(
const BorderSide(
color: Colors.black,
width: 1.5,
style: BorderStyle.solid),
),
),
),
const SizedBox(width: 20.0),
TextButton(
onPressed: _isTransacting
? null
: () {
_createTransaction(
user.$id.toString(),
user.name,
user.balance,
);
},
child: Text(
'Spend from wallet',
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
color: Colors.white),
),
style: ButtonStyle(
backgroundColor:
MaterialStateProperty.all(Colors.black),
side: MaterialStateProperty.all(
const BorderSide(
color: Colors.black,
width: 1.5,
style: BorderStyle.solid),
),
padding:
MaterialStateProperty.all<EdgeInsets>(
const EdgeInsets.symmetric(
horizontal: 15.0),
)),
),
],
),
)
],
),
),
);
}
}
لیست معاملات را دریافت کنید
برای به دست آوردن لیست تراکنش ها، باید آن را اصلاح کنیم transactions.dart
فایل در همان screens
دایرکتوری مطابق شکل زیر:
import 'package:flutter/material.dart';
import 'package:mobile_wallet/utils.dart';
import 'package:mobile_wallet/wallet_service.dart';
class Transactions extends StatefulWidget {
const Transactions({super.key});
@override
State<Transactions> createState() => _TransactionsState();
}
class _TransactionsState extends State<Transactions> {
late List<Transaction> transaction;
bool _isLoading = false;
bool _isError = false;
@override
void initState() {
_getTransactions();
super.initState();
}
_getTransactions() {
setState(() {
_isLoading = true;
});
WalletService().getTransactions().then((value) {
setState(() {
transaction = value;
_isLoading = false;
});
}).catchError((e) {
setState(() {
_isLoading = false;
_isError = true;
});
});
}
@override
Widget build(BuildContext context) {
return _isLoading
? const Center(
child: CircularProgressIndicator(
color: Colors.blue,
))
: _isError
? const Center(
child: Text(
'Error getting list of transactions',
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
),
)
: Scaffold(
appBar: AppBar(
title: const Text('Transactions'),
backgroundColor: Colors.black,
),
body: ListView.builder(
itemCount: transaction.length,
itemBuilder: (context, index) {
return Container(
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(width: .5, color: Colors.grey),
),
),
padding: EdgeInsets.fromLTRB(10, 20, 10, 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
flex: 7,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
transaction[index].name,
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800),
),
SizedBox(height: 10.0),
Text(transaction[index].paymentMethod)
],
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(height: 10.0),
Text('\$ ${transaction[index].amount}')
],
),
],
),
);
},
),
);
}
}
قطعه بالا کارهای زیر را انجام می دهد:
- خطوط 1-3: وابستگی های مورد نیاز را وارد کنید
-
خطوط 11-13: ایجاد کنید
transactions
،_isLoading
، و_isError
خواص برای مدیریت وضعیت برنامه -
خطوط 15-36: ایجاد یک
_getTransactions
روشی برای دریافت لیست تراکنش ها با استفاده ازWalletService().getTransactions
سرویس، وضعیت ها را بر اساس آن تنظیم کنید و از آن استفاده کنیدinitState
روش فراخوانی_getTransactions
زمانی که شی به درخت وارد می شود - ویجت های رابط کاربری را برای نمایش تراکنش های ذخیره شده در Appwrite تغییر می دهد
پس از انجام این کار، برنامه را با استفاده از ویرایشگر کد راه اندازی مجدد می کنیم یا دستور زیر را اجرا می کنیم:
flutter run
https://media.giphy.com/media/f7i8RWsiXAIdXDOoBW/giphy.gif
نتیجه
در این پست نحوه استفاده از ویژگی های پایگاه داده Appwrite برای ساخت یک عملکرد کیف پول موبایل در یک برنامه Flutter بحث شده است. ما یک پیادهسازی پایه برای نشان دادن پشتیبانی Appwrite از داربست یک نمونه اولیه ساختیم. با Appwrite، میتوانیم با استفاده از ویژگیهایی مانند ارتباطات بلادرنگ، محلیسازی، احراز هویت و غیره، عملکرد برنامه را بیشتر گسترش دهیم.
این منابع ممکن است مفید باشند: