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
2 changes: 1 addition & 1 deletion scgateway/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.smallcase.gateway:sdk:6.0.5'
implementation 'com.smallcase.gateway:sdk:6.0.6'
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,13 @@ import com.smallcase.gateway.data.models.*
import com.smallcase.gateway.data.requests.InitRequest
import com.smallcase.gateway.portal.SmallcaseGatewaySdk
import com.smallcase.gateway.portal.SmallplugPartnerProps
import com.smallcase.gateway.data.listeners.Notification
import com.smallcase.gateway.data.listeners.NotificationCenter
import com.smallcase.gateway.portal.ScgNotification
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import io.flutter.plugin.common.EventChannel
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
Expand Down Expand Up @@ -46,13 +50,43 @@ class ScgatewayFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {
/// This local reference serves to register the plugin with the Flutter Engine and unregister it
/// when the Flutter Engine is detached from the Activity
private lateinit var channel: MethodChannel

private lateinit var eventChannel: EventChannel
private var eventSink: EventChannel.EventSink? = null
private var notificationObserver: ((Notification) -> Unit)? = null

override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
this.context = flutterPluginBinding.applicationContext

channel = MethodChannel(flutterPluginBinding.binaryMessenger, "scgateway_flutter_plugin")
channel.setMethodCallHandler(this)

eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "scgateway_flutter_plugin/smallplug_events")
eventChannel.setStreamHandler(object : EventChannel.StreamHandler {
override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
notificationObserver = { notification ->
processSmallplugNotification(notification)
}
notificationObserver?.let { NotificationCenter.addObserver(it) }
}
override fun onCancel(arguments: Any?) {
notificationObserver?.let { NotificationCenter.removeObserver(it) }
notificationObserver = null
eventSink = null
}
})
}

private fun processSmallplugNotification(notification: Notification) {
val jsonString = notification.userInfo?.get(ScgNotification.STRINGIFIED_PAYLOAD_KEY) as? String ?: return
try {
val parsed = org.json.JSONObject(jsonString)
if (parsed.optString("type") != "smallplug_analytics_event") return
val eventData = parsed.optJSONObject("data") ?: return
uiThreadHandler.post {
eventSink?.success(eventData.toString())
}
} catch (_: Exception) {}
}

override fun onMethodCall(@NonNull call: MethodCall, @NonNull rawResult: Result) {
Expand Down Expand Up @@ -495,6 +529,9 @@ class ScgatewayFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware {

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
channel.setMethodCallHandler(null)
notificationObserver?.let { NotificationCenter.removeObserver(it) }
notificationObserver = null
eventSink = null
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
Expand Down
53 changes: 45 additions & 8 deletions scgateway/ios/Classes/SwiftScgatewayFlutterPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,57 @@ enum IntentType: String {
case authoriseHoldings = "AUTHORISE_HOLDINGS"
}

public class SwiftScgatewayFlutterPlugin: NSObject, FlutterPlugin {
public class SwiftScgatewayFlutterPlugin: NSObject, FlutterPlugin, FlutterStreamHandler {

@MainActor
let currentViewController: UIViewController = (UIApplication.shared.delegate?.window??.rootViewController)!


private var eventSink: FlutterEventSink?
private var notificationObserver: NSObjectProtocol?

public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "scgateway_flutter_plugin", binaryMessenger: registrar.messenger())
let instance = SwiftScgatewayFlutterPlugin()
// let scLoansChannel = FlutterMethodChannel(name: "scloans", binaryMessenger: registrar.messenger())
// let scLoansInstance = ScLoanFlutterPlugin()

let eventChannel = FlutterEventChannel(name: "scgateway_flutter_plugin/smallplug_events", binaryMessenger: registrar.messenger())
eventChannel.setStreamHandler(instance)

registrar.addMethodCallDelegate(instance, channel: channel)
// registrar.addMethodCallDelegate(scLoansInstance, channel: scLoansChannel)
}

// MARK: - FlutterStreamHandler (SmallPlug event streaming)

public func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = events
notificationObserver = NotificationCenter.default.addObserver(
forName: SCGateway.scgNotificationName,
object: nil,
queue: .main
) { [weak self] notification in
self?.handleScgNotification(notification)
}
return nil
}

public func onCancel(withArguments arguments: Any?) -> FlutterError? {
if let observer = notificationObserver {
NotificationCenter.default.removeObserver(observer)
notificationObserver = nil
}
eventSink = nil
return nil
}

private func handleScgNotification(_ notification: Notification) {
guard let jsonString = notification.userInfo?[SCGNotification.strigifiedPayloadKey] as? String,
let data = jsonString.data(using: .utf8),
let parsed = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
parsed["type"] as? String == NotificationTypes.smallplugAnalyticsEvent,
let eventData = parsed["data"] as? [String: Any] else { return }
guard let sink = eventSink,
let eventJson = try? JSONSerialization.data(withJSONObject: eventData),
let eventString = String(data: eventJson, encoding: .utf8) else { return }
sink(eventString)
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
Expand Down
2 changes: 1 addition & 1 deletion scgateway/ios/scgateway_flutter_plugin.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Scgateway Flutter plugin.
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.dependency 'SCGateway', '7.1.4'
s.dependency 'SCGateway', '7.1.7'
s.xcconfig = {'BUILD_LIBRARY_FOR_DISTRIBUTION' => 'YES'}
s.vendored_frameworks = 'SCGateway.xcframework'
s.platform = :ios, '13.0'
Expand Down
34 changes: 34 additions & 0 deletions scgateway/lib/scgateway_flutter_plugin.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import './color_ext.dart';
Expand Down Expand Up @@ -46,10 +47,43 @@ class SmallplugUiConfig {
};
}

class SmallplugAnalyticsEvent {
final String eventName;
final Map<String, dynamic> data;
final double timestamp;

SmallplugAnalyticsEvent({
required this.eventName,
required this.data,
required this.timestamp,
});

factory SmallplugAnalyticsEvent.fromJson(Map<String, dynamic> json) {
return SmallplugAnalyticsEvent(
eventName: json['eventName'] as String? ?? '',
data: (json['data'] as Map?)?.cast<String, dynamic>() ?? {},
timestamp: (json['timestamp'] as num?)?.toDouble() ?? 0,
);
}
}

class ScgatewayFlutterPlugin {
static const MethodChannel _channel =
const MethodChannel('scgateway_flutter_plugin');

static const EventChannel _smallplugEventChannel =
EventChannel('scgateway_flutter_plugin/smallplug_events');

/// Stream of SmallPlug / DM analytics events.
/// Subscribe before calling [launchSmallplug] or [launchSmallplugWithBranding].
static Stream<SmallplugAnalyticsEvent> get smallplugEventStream {
return _smallplugEventChannel.receiveBroadcastStream().map((event) {
final Map<String, dynamic> json =
(event is String ? jsonDecode(event) : event) as Map<String, dynamic>;
return SmallplugAnalyticsEvent.fromJson(json);
});
}

static const String _flutterPluginVersion = "4.0.0";

static Future<String?> getSdkVersion() async {
Expand Down
2 changes: 1 addition & 1 deletion scgateway/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: scgateway_flutter_plugin
description: Scgateway Flutter plugin.
version: 7.0.5
version: 7.0.6
homepage: https://github.com/smallcase/gw-mob-sdk-flutter

# The following line prevents the package from being accidentally published to
Expand Down
10 changes: 10 additions & 0 deletions smart_investing/lib/main.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:go_router/go_router.dart';
import 'package:scgateway_flutter_plugin/scgateway_flutter_plugin.dart';

import 'app/SIGatewayPage.dart';
import 'app/SILoansPage.dart';
Expand All @@ -20,6 +23,7 @@ class MyApp extends StatefulWidget {

class _MyAppState extends State<MyApp> {
late Brightness _brightness;
StreamSubscription? _smallplugEventSub;

@override
void initState() {
Expand All @@ -31,11 +35,17 @@ class _MyAppState extends State<MyApp> {
_brightness = dispatcher.platformBrightness;
});
};
_smallplugEventSub =
ScgatewayFlutterPlugin.smallplugEventStream.listen((event) {
print(
'[SmallplugEvent] ${event.eventName} | data: ${event.data} | ts: ${event.timestamp}');
});
super.initState();
}

@override
void dispose() {
_smallplugEventSub?.cancel();
repository.dispose();
super.dispose();
}
Expand Down
2 changes: 1 addition & 1 deletion smart_investing/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 3.0.7
version: 3.0.8

environment:
sdk: ^3.8.1
Expand Down