Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,64 @@
# paystack_flutter

A new Flutter plugin project.
A [Paystack](https://paystack.com) plugin for accepting payments in your Flutter application.

## Minimum Requirement
Paystack Flutter SDK builds upon the recent patterns in the Android and iOS, thus your app should target:
- Android 6.0 (API level 23) and above
- iOS 13 and above

> [! Android Gotcha]
> Flutter (3.3.0 below, at the moment) extends the `FlutterActivity` as the base class for Android. The `FlutterActivity` doesn't have the `ComponentActivity`, a compulsory necessity for loading the payment views with the SDK, in its ancestral tree. To fix this, change the `FlutterActivity` to `FlutterFragmentActivity` in the `MainActivity` in the `android` folder of your project.

## Getting Started
- Install the dependency in your project
```sh
flutter pub get link_coming_soon
```
- Import the paystack_flutter into your `.dart` file
```dart
import 'package:paystack_flutter/paystack.dart';
```
- Use the plugin
```dart
final _publicKey = "pk_domain_xxxxxx";
final _accessCode = "67joTry7t1jz2o";
final _paystack = Paystack();

initialize(String publicKey) async {
try {
final response = await _paystack.initialize(publicKey, true);
if (response) {
log("Sucessfully initialised the SDK");
} else {
log("Unable to initialise the SDK");
}
} on PlatformException catch (e) {
log(e.message!);
}
}

launch() async {
String reference = "";
try {
final response = await _paystack.launch(_accessCode);
if (response.status) {
reference = response.reference;
log(reference);
} else {
log(response.message);
}
} on PlatformException catch (e) {
log(e.message!);
}

setState(() {
_reference = reference;
});
}
```

This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
## License
WIP

For help getting started with Flutter development, view the
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.paystack.paystack_flutter

import android.util.Log
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import com.paystack.android.core.Paystack
Expand All @@ -20,54 +19,94 @@ class PaystackFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var channel : MethodChannel
private lateinit var paymentSheet: PaymentSheet
private var activity: FlutterFragmentActivity? = null
private lateinit var pendingResult: Result

private fun initializePaystack(publicKey: String, enableLogging: Boolean) {
Paystack
.builder()
.setPublicKey(publicKey)
.setLoggingEnabled(enableLogging)
.build()
override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.paystack.flutter")
channel.setMethodCallHandler(this)
}

private fun launch(accessCode: String) {
paymentSheet.launch(accessCode)
// TODO: Change error codes to numbers and provide documentation for it
override fun onMethodCall(call: MethodCall, result: Result) {
pendingResult = result
when (call.method) {
"initialize" -> {
val publicKey = call.argument<String>("publicKey")
val enableLogging = call.argument<Boolean>("enableLogging") ?: false
if (publicKey.isNullOrEmpty()) {
result.error("INVALID_ARGUMENTS", "Missing public key", null)
return
}
initialize(publicKey, enableLogging)
}
"launch" -> {
val accessCode = call.argument<String>("accessCode")
if(accessCode.isNullOrEmpty()) {
result.error("INVALID_ARGUMENTS", "Missing access code", null)
return
}
launch(accessCode)
}
else -> result.notImplemented()
}
}

// TODO: Change return from String to PaymentSheetResult
// This will require create the same response model in Flutter
private fun paymentComplete(paymentSheetResult: PaymentSheetResult): String {
val response = when (paymentSheetResult) {
is PaymentSheetResult.Cancelled -> "Cancelled"
is PaymentSheetResult.Failed -> paymentSheetResult.error.message ?: "Failed"
is PaymentSheetResult.Completed -> {
paymentSheetResult.paymentCompletionDetails.reference
}
private fun initialize(publicKey: String, enableLogging: Boolean) {
try {
Paystack
.builder()
.setPublicKey(publicKey)
.setLoggingEnabled(enableLogging)
.build()
pendingResult.success(true)
} catch (e: Exception) {
pendingResult.error("INITIALIZATION_ERROR", e.message, null)
}

return response
// pendingResult = null
}

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
channel = MethodChannel(flutterPluginBinding.binaryMessenger, "com.paystack.flutter")
channel.setMethodCallHandler(this)
private fun launch(accessCode: String) {
if (activity == null) {
pendingResult.error("NO_ACTIVITY", "Activity is not available", null)
return
}

try {
paymentSheet.launch(accessCode)
} catch (e: Exception) {
pendingResult.error("LAUNCH_ERROR", e.message, null)
return
}

// pendingResult = null
}

// TODO: Return object in result as opposed to String
override fun onMethodCall(call: MethodCall, result: Result) {
when (call.method) {
"getPlatformVersion" -> result.success("Android ${android.os.Build.VERSION.RELEASE}")
"build" -> {
initializePaystack(
call.argument("publicKey") ?: "",
call.argument("enableLogging") ?: false)
result.success("Initiated")
private fun paymentComplete(paymentSheetResult: PaymentSheetResult) {
when (paymentSheetResult) {
is PaymentSheetResult.Completed -> {
pendingResult.success(mapOf(
"status" to true,
"message" to "Transaction successful",
"reference" to paymentSheetResult.paymentCompletionDetails.reference
))
}
"launch" -> {
launch(call.argument("accessCode") ?: "")
result.success("Launch called")
is PaymentSheetResult.Cancelled -> {
pendingResult.success(mapOf(
"status" to false,
"message" to "Transaction cancelled",
"reference" to ""
))
}
is PaymentSheetResult.Failed -> {
pendingResult.success(mapOf(
"status" to "failed",
"message" to paymentSheetResult.error.message,
"reference" to ""
))
}
else -> result.notImplemented()
}
// pendingResult = null
}

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
Expand All @@ -76,12 +115,10 @@ class PaystackFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
activity = binding.activity as FlutterFragmentActivity
Log.d("ACTIVITY: ", "Attached")
(binding.lifecycle as HiddenLifecycleReference)
.lifecycle
.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_CREATE) {
Log.d("OBSERVER: ", "In observer")
val activity = requireNotNull(activity)
paymentSheet = PaymentSheet(activity, ::paymentComplete)
}
Expand Down
40 changes: 20 additions & 20 deletions example/ios/Flutter/AppFrameworkInfo.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>12.0</string>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>App</string>
<key>CFBundleIdentifier</key>
<string>io.flutter.flutter.app</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>App</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>14.0</string>
</dict>
</plist>
6 changes: 0 additions & 6 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
PODS:
- Flutter (1.0.0)
- paystack_flutter (0.0.1):
- Flutter

DEPENDENCIES:
- Flutter (from `Flutter`)
- paystack_flutter (from `.symlinks/plugins/paystack_flutter/ios`)

EXTERNAL SOURCES:
Flutter:
:path: Flutter
paystack_flutter:
:path: ".symlinks/plugins/paystack_flutter/ios"

SPEC CHECKSUMS:
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
paystack_flutter: 2473137a59e6883a1d76de6a4c5116bb1a776270

PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796

Expand Down
Loading