Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GH-62: adding jwt-enabled API keys #67

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
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
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
example/ios/Podfile.lock
example/pubspec.lock
example/pubspec.lock
.dart_tool/
build/
pubspec.lock
7 changes: 5 additions & 2 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdkVersion 31
compileSdkVersion 33

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand All @@ -42,7 +42,10 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation 'com.iterable:iterableapi:3.4.9'
implementation 'com.iterable:iterableapi:3.4.15'
implementation 'com.iterable:iterableapi-ui:3.4.0'
// Version 17.4.0+ is required for push notifications and in-app message features:
implementation 'com.google.firebase:firebase-messaging:17.4.0'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.json:json:20210307'
}
1 change: 1 addition & 0 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.lahaus.iterable_flutter">
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import org.json.JSONObject
import java.util.*
import java.net.URL



/** IterableFlutterPlugin */
Expand Down Expand Up @@ -52,9 +54,9 @@ class IterableFlutterPlugin : FlutterPlugin, MethodCallHandler {
result.success(null)
}
"setEmail" -> {
val userEmail = call.arguments as String
IterableApi.getInstance().setEmail(userEmail)
IterableApi.getInstance().registerForPush()
val email = call.argument<String>("email") ?: ""
val jwt = call.argument<String>("jwt") ?: ""
IterableApi.getInstance().setEmail(email, jwt)
result.success(null)
}
"setUserId" -> {
Expand Down Expand Up @@ -93,6 +95,14 @@ class IterableFlutterPlugin : FlutterPlugin, MethodCallHandler {
IterableApi.getInstance().updateUser(JSONObject(userInfo))
result.success(null)
}
"handleDeepLink" -> {
val argumentData = call.arguments as? Map<*, *>
val url = argumentData?.get("url") as String
IterableApi.getInstance().getAndTrackDeepLink(url) { result:String? ->
Log.d("HandleDeeplink", "Redirected to: $result")
channel.invokeMethod("deepLinkHandler", mapOf("path" to URL(result).path))
}
}
else -> {
result.notImplemented()
}
Expand All @@ -107,11 +117,10 @@ class IterableFlutterPlugin : FlutterPlugin, MethodCallHandler {
notifyPushNotificationOpened()
false
}

if (activeLogDebug) {
configBuilder.setLogLevel(Log.DEBUG)
configBuilder.setLogLevel(Log.VERBOSE)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably not necessary to include in the PR and probably makes sense to change locally when you need to check logs for something.

}

IterableApi.initialize(context, apiKey, configBuilder.build())
}

Expand Down
4 changes: 2 additions & 2 deletions example/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ apply from: project(':flutter_config').projectDir.getPath() + "/dotenv.gradle"
apply plugin: 'com.google.gms.google-services'

android {
compileSdkVersion 31
compileSdkVersion 33

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
Expand All @@ -39,7 +39,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.lahaus.iterable_flutter_example"
minSdkVersion 16
targetSdkVersion 31
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
Expand Down
59 changes: 48 additions & 11 deletions ios/Classes/SwiftIterableFlutterPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,34 @@ import UIKit
import IterableSDK
import UserNotifications

public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotificationCenterDelegate, IterableCustomActionDelegate, IterableURLDelegate {
public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotificationCenterDelegate, IterableCustomActionDelegate, IterableURLDelegate, IterableAuthDelegate {

static var channel: FlutterMethodChannel? = nil
var token: String? = nil

public static func register(with registrar: FlutterPluginRegistrar) {
NSLog("calling channel register")
channel = FlutterMethodChannel(name: "iterable_flutter", binaryMessenger: registrar.messenger())
let instance = SwiftIterableFlutterPlugin()
registrar.addMethodCallDelegate(instance, channel: channel!)

registrar.addApplicationDelegate(instance)
}

public func onAuthTokenRequested(completion: @escaping AuthTokenRetrievalHandler) {
print("calling onAuthTokenRequested")
print(token)
completion(token)
}

public func onAuthFailure(_ authFailure: AuthFailure) {

}

public func onTokenRegistrationFailed(_ reason: String?) {
print("token registration failed")
print(reason)
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
switch (call.method) {
Expand All @@ -22,14 +39,17 @@ public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotifica

let apiKey = args["apiKey"] as! String
let pushIntegrationName = args["pushIntegrationName"] as! String

initialize(apiKey, pushIntegrationName)

result(nil)
case "setEmail":
let email = call.arguments as! String
IterableAPI.email = email

let args = getPropertiesFromArguments(call.arguments)
let email = args["email"] as! String
let jwt = args["jwt"] as! String
print("calling IterableAPI.setEmail")
token = jwt
IterableAPI.setEmail(email, jwt)
print("finished calling IterableAPI.setEmail")
result(nil)
case "setUserId":
let userId = call.arguments as! String
Expand Down Expand Up @@ -67,6 +87,14 @@ public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotifica
case "signOut":
signOut()

result(nil)
case "handleDeepLink":
NSLog("NSLog handleDeepLink")
let args = getPropertiesFromArguments(call.arguments)
let urlStr = args["url"] as! String
NSLog("deeplink \(urlStr)")
let url = URL(string: urlStr)
IterableAPI.handle(universalLink: url!)
result(nil)
default:
result(FlutterMethodNotImplemented)
Expand All @@ -76,10 +104,11 @@ public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotifica
private func initialize(_ apiKey: String, _ pushIntegrationName: String){
let config = IterableConfig()
config.pushIntegrationName = pushIntegrationName
config.autoPushRegistration = true
config.autoPushRegistration = false
config.customActionDelegate = self
config.urlDelegate = self

config.authDelegate = self
config.logDelegate = AllLogDelegate()
IterableAPI.initialize(apiKey: apiKey, config: config)
}

Expand All @@ -95,12 +124,14 @@ public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotifica
}

public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [AnyHashable : Any] = [:]) -> Bool {
print("application")
UNUserNotificationCenter.current().delegate = self

return true
}

public func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
print("~~~~~ calling IterableAPI.register")
IterableAPI.register(token: deviceToken)
}

Expand Down Expand Up @@ -132,7 +163,15 @@ public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotifica


public func handle(iterableURL url: URL, inContext context: IterableActionContext) -> Bool {
notifyPushNotificationOpened()
NSLog("deeplink: handle(iterableURL url: URL,")
NSLog("deeplink \(url.path)")
let payload = [
"path": url.path ?? "",
"query": url.query ?? ""
] as [String : Any]
NSLog("calling deepLinkHandler up the channel")
NSLog("is there a channel? \(SwiftIterableFlutterPlugin.channel == nil)")
SwiftIterableFlutterPlugin.channel?.invokeMethod("deepLinkHandler", arguments: payload)
return true
}

Expand All @@ -151,7 +190,5 @@ public class SwiftIterableFlutterPlugin: NSObject, FlutterPlugin, UNUserNotifica
] as [String : Any]

SwiftIterableFlutterPlugin.channel?.invokeMethod("openedNotificationHandler", arguments: payload)

}

}
2 changes: 1 addition & 1 deletion ios/iterable_flutter.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Pod::Spec.new do |s|
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.dependency 'Flutter'
s.dependency 'Iterable-iOS-SDK', '6.4.7'
s.dependency 'Iterable-iOS-SDK', '6.5.7'
s.platform = :ios, '11.0'

# Flutter.framework does not contain a i386 slice.
Expand Down
33 changes: 28 additions & 5 deletions lib/iterable_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,19 @@ import 'dart:convert';
import 'package:flutter/services.dart';

typedef OpenedNotificationHandler = void Function(Map openedResult);
typedef OpenedDeepLinkHandler = void Function(Map openedResult);

// ignore: avoid_classes_with_only_static_members
class IterableFlutter {
static const MethodChannel _channel = MethodChannel('iterable_flutter');

static OpenedNotificationHandler? _onOpenedNotification;
static OpenedDeepLinkHandler? _onOpenedDeepLink;

static Future<void> initialize({
required String apiKey,
required String pushIntegrationName,
bool activeLogDebug = false,
bool activeLogDebug = false
}) async {
await _channel.invokeMethod(
'initialize',
Expand All @@ -27,8 +29,20 @@ class IterableFlutter {
_channel.setMethodCallHandler(nativeMethodCallHandler);
}

static Future<void> setEmail(String email) async {
await _channel.invokeMethod('setEmail', email);
static Future<void> setEmail(String email, String jwt) async {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would make jwt nullable in order to communicate that it isn't strictly required. Some implementations either don't care about having a JWT, or just want to get something quick put together to ensure the package works.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No support for setUserId? Seems easy enough to add.

await _channel.invokeMethod(
'setEmail',
{
'email': email,
'jwt': jwt,
},
);
}

static Future<void> handleDeepLink(url) async {
print("handleDeepLink");
print(url);
await _channel.invokeMethod("handleDeepLink", {'url': url});
}

static Future<void> setUserId(String userId) async {
Expand Down Expand Up @@ -69,14 +83,23 @@ class IterableFlutter {
_onOpenedNotification = handler;
}

static void setDeepLinkOpenedHandler(OpenedDeepLinkHandler handler) {
print("calling setDeepLinkOpenedHandler ");
_onOpenedDeepLink = handler;
}

static Future<dynamic> nativeMethodCallHandler(MethodCall methodCall) async {
print("nativeMethodCallHandler maybe deep? ${methodCall.method}");
final arguments = methodCall.arguments as Map<dynamic, dynamic>;
final argumentsCleaned = sanitizeArguments(arguments);

switch (methodCall.method) {
case "openedNotificationHandler":
_onOpenedNotification?.call(argumentsCleaned);
return "This data from native.....";
case "deepLinkHandler":
print("deepLinkHandler running... ");
_onOpenedDeepLink?.call(argumentsCleaned);
return "Deep link datta from handler...";
default:
return "Nothing";
}
Expand All @@ -86,7 +109,7 @@ class IterableFlutter {
Map<dynamic, dynamic> arguments) {
final result = arguments;

final data = result['additionalData'];
final data = result['additionalData'] ?? {};
data.forEach((key, value) {
if (value is String) {
if (value[0] == '{' && value[value.length - 1] == '}') {
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: iterable_flutter
description: Flutter implementation for iterable.com Cross Channel Marketing Platform
version: 0.5.8
version: 0.9.3
homepage: https://lahaus.com
repository: https://github.com/la-haus/iterable-flutter
issue_tracker: https://github.com/la-haus/iterable-flutter/issues
Expand Down
12 changes: 9 additions & 3 deletions test/iterable_flutter_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ void main() {
const String activeLogDebug = 'activeLogDebug';
const String email = '[email protected]';
const String userId = '11111';
const String jwt = '';
const String event = 'my_event';
const String authToken = 'authToken';
const Map<String, dynamic> dataFields = {'data': 'field'};

const contentBody = {'testKey': "Test body push"};
Expand Down Expand Up @@ -64,16 +66,20 @@ void main() {
arguments: {
apiKey: apiKey,
pushIntegrationName: pushIntegrationName,
activeLogDebug: false
activeLogDebug: false,
authToken: null
},
),
]);
});

test('setEmail', () async {
await IterableFlutter.setEmail(email);
await IterableFlutter.setEmail(email, jwt);
expect(calledMethod, <Matcher>[
isMethodCall('setEmail', arguments: email),
isMethodCall('setEmail', arguments: {
"email": email,
"jwt": jwt
}),
]);
});

Expand Down