From d926364574ba1c1e5ce6adb25de88e561e6481e9 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Tue, 5 Mar 2024 15:39:55 -0800 Subject: [PATCH 01/11] refactor: update ios bridge --- .../AmplitudeFlutterPlugin.kt | 1 + example/ios/Podfile | 2 +- example/ios/Podfile.lock | 20 +- example/ios/Runner.xcodeproj/project.pbxproj | 6 +- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 516 ++++++++++-------- ios/amplitude_flutter.podspec | 4 +- 6 files changed, 303 insertions(+), 246 deletions(-) diff --git a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt index ae1e9ba..ad1590f 100644 --- a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt +++ b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt @@ -237,6 +237,7 @@ class AmplitudeFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { (map["deviceManufacturer"] as? Boolean)?.let { if (!it) trackingOptions.disableDeviceManufacturer() } (map["osVersion"] as? Boolean)?.let { if (!it) trackingOptions.disableOsVersion() } (map["osName"] as? Boolean)?.let { if (!it) trackingOptions.disableOsName() } + (map["versionName"] as? Boolean)?.let { if (!it) trackingOptions.disableVersionName() } (map["adid"] as? Boolean)?.let { if (!it) trackingOptions.disableAdid() } (map["appSetId"] as? Boolean)?.let { if (!it) trackingOptions.disableAppSetId() } (map["deviceBrand"] as? Boolean)?.let { if (!it) trackingOptions.disableDeviceBrand() } diff --git a/example/ios/Podfile b/example/ios/Podfile index 9411102..10f3c9b 100644 --- a/example/ios/Podfile +++ b/example/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -platform :ios, '10.0' +platform :ios, '13.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 214938e..1ac8370 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -1,8 +1,10 @@ PODS: - - Amplitude (8.16.1) - amplitude_flutter (0.0.1): - - Amplitude (= 8.16.1) + - AmplitudeSwift (~> 1.0.0) - Flutter + - AmplitudeSwift (1.0.0): + - AnalyticsConnector (~> 1.0.1) + - AnalyticsConnector (1.0.3) - Flutter (1.0.0) DEPENDENCIES: @@ -11,7 +13,8 @@ DEPENDENCIES: SPEC REPOS: trunk: - - Amplitude + - AmplitudeSwift + - AnalyticsConnector EXTERNAL SOURCES: amplitude_flutter: @@ -20,10 +23,11 @@ EXTERNAL SOURCES: :path: Flutter SPEC CHECKSUMS: - Amplitude: ef9ed339ddd33c9183edf63fa4bbaa86cf873321 - amplitude_flutter: 8ddb231989e68ed8c005c838d7fc59edbca09833 - Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a + amplitude_flutter: 16812bda98a0de430b0021dbd59648c84b76f9ed + AmplitudeSwift: 17755f7599198721c32e26b884423759c2daec7d + AnalyticsConnector: a53214d38ae22734c6266106c0492b37832633a9 + Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 -PODFILE CHECKSUM: fe0e1ee7f3d1f7d00b11b474b62dd62134535aea +PODFILE CHECKSUM: cc1f88378b4bfcf93a6ce00d2c587857c6008d3b -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.1 diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index b0b9f94..387b2e8 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -215,12 +215,14 @@ ); inputPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", - "${BUILT_PRODUCTS_DIR}/Amplitude/Amplitude.framework", + "${BUILT_PRODUCTS_DIR}/AmplitudeSwift/AmplitudeSwift.framework", + "${BUILT_PRODUCTS_DIR}/AnalyticsConnector/AnalyticsConnector.framework", "${BUILT_PRODUCTS_DIR}/amplitude_flutter/amplitude_flutter.framework", ); name = "[CP] Embed Pods Frameworks"; outputPaths = ( - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Amplitude.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AmplitudeSwift.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/AnalyticsConnector.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/amplitude_flutter.framework", ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 3c5ff32..967fc9c 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -1,252 +1,302 @@ import Flutter import UIKit -import Amplitude +import AmplitudeSwift @objc public class SwiftAmplitudeFlutterPlugin: NSObject, FlutterPlugin { + var amplitude: Amplitude? + static let methodChannelName = "amplitude_flutter" + public static func register(with registrar: FlutterPluginRegistrar) { - let channel = FlutterMethodChannel(name: "amplitude_flutter", binaryMessenger: registrar.messenger()) + let channel = FlutterMethodChannel(name: methodChannelName, binaryMessenger: registrar.messenger()) let instance = SwiftAmplitudeFlutterPlugin() registrar.addMethodCallDelegate(instance, channel: channel) } - public func getPropertiesFromArguments(_ callArguments: Any?) throws -> [String:Any]? { - if let arguments = callArguments, let data = (arguments as! String).data(using: .utf8) { + public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { + switch call.method { + case "init": + + amplitude = Amplitude(configuration: getConfiguration(call: call)) + + // TODO(xinyi): add library plugin + amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") + + // TODO(xinyi): check app lifecycle events + + result("init called..") + + case "track": + let event = getEvent(call: call) + amplitude?.track(event: event) + amplitude?.logger?.debug(message: "Track event: \(String(describing: call.arguments))") + + result("track called..") + + case "identify": + let event = getEvent(call: call) + amplitude?.track(event: event) + amplitude?.logger?.debug(message: "Track identify event: \(String(describing: call.arguments))") + + result("identify called..") + + case "groupIdentify": + let event = getEvent(call: call) + amplitude?.track(event: event) + amplitude?.logger?.debug(message: "Track group identify event: \(String(describing: call.arguments))") + + result("groupIdentify called..") + + case "setGroup": + let event = getEvent(call: call) + amplitude?.track(event: event) + amplitude?.logger?.debug(message: "Track set group event: \(String(describing: call.arguments))") + + result("setGroup called..") + + case "revenue": + let event = getEvent(call: call) + amplitude?.track(event: event) + amplitude?.logger?.debug(message: "Track revenue event: \(String(describing: call.arguments))") + + result("revenue called..") + + case "setUserId": + let args = call.arguments as! [String: String] + let userId = args["setUserId"] + amplitude?.setUserId(userId: userId) + amplitude?.logger?.debug(message: "Set user Id to \(String(describing: userId))") + + result("serUserId called..") + + case "setDeviceId": + let args = call.arguments as! [String: String] + let deviceId = args["setDeviceId"] + amplitude?.setDeviceId(deviceId: deviceId) + amplitude?.logger?.debug(message: "Set device Id to \(String(describing: deviceId))") + + result("setDeviceId called..") + + case "reset": + amplitude?.reset() + amplitude?.logger?.debug(message: "Reset userId and deviceId.") + + result("reset called..") + + case "flush": + amplitude?.flush() + amplitude?.logger?.debug(message: "Flush events.") + + result("flush called..") - let properties = try JSONSerialization.jsonObject(with: data, options: []) as! [String:Any] - return properties; + default: + amplitude?.logger?.debug(message: "Method \(call.method) is not recognized.") + result(FlutterMethodNotImplemented) + } + } + + private func getConfiguration(call: FlutterMethodCall) -> Configuration { + let args = call.arguments as! [String: Any] + let apiKey = args["apiKey"] as! String + + let instanceName = args["instanceName"] as! String + let migrateLegacyData = args["migrateLegacyData"] as! Bool + + let configuration = Configuration(apiKey: apiKey, instanceName: instanceName, migrateLegacyData: migrateLegacyData) + + if let flushQueueSize = args["flushQueueSize"] as? Int { + configuration.flushQueueSize = flushQueueSize + } + if let flushIntervalMillis = args["flushIntervalMillis"] as? Int { + configuration.flushIntervalMillis = flushIntervalMillis + } + if let optOut = args["optOut"] as? Bool { + configuration.optOut = optOut + } + if let logLevel = args["logLevel"] as? String { + configuration.logLevel = logLevelFromString(logLevel) + } + if let minIdLength = args["minIdLength"] as? Int { + configuration.minIdLength = minIdLength + } + if let partnerId = args["partnerId"] as? String { + configuration.partnerId = partnerId + } + if let flushMaxRetries = args["flushMaxRetries"] as? Int { + configuration.flushMaxRetries = flushMaxRetries } - return nil; + if let useBatch = args["useBatch"] as? Bool { + configuration.useBatch = useBatch + } + if let serverZone = args["serverZone"] as? String, let serverZoneValue = ServerZone(rawValue: serverZone.uppercased()) { + configuration.serverZone = serverZoneValue + } + if let serverUrl = args["serverUrl"] as? String { + configuration.serverUrl = serverUrl + } + if let trackingOptionsDict = args["trackingOptions"] as? [String: Any] { + configuration.trackingOptions = convertMapToTrackingOptions(map: trackingOptionsDict) + } + if let enableCoppaControl = args["enableCoppaControl"] as? Bool { + configuration.enableCoppaControl = enableCoppaControl + } + if let flushEventsOnClose = args["flushEventsOnClose"] as? Bool { + configuration.flushEventsOnClose = flushEventsOnClose + } + if let minTimeBetweenSessionsMillis = args["minTimeBetweenSessionsMillis"] as? Int { + configuration.minTimeBetweenSessionsMillis = minTimeBetweenSessionsMillis + } + if let identifyBatchIntervalMillis = args["identifyBatchIntervalMillis"] as? Int { + configuration.identifyBatchIntervalMillis = identifyBatchIntervalMillis + } + if let defaultTrackingDict = args["defaultTracking"] as? [String: Bool] { + let sessions = defaultTrackingDict["sessions"] ?? true + let appLifecycles = defaultTrackingDict["appLifecycles"] ?? false + let screenViews = defaultTrackingDict["screenViews"] ?? false + configuration.defaultTracking = DefaultTrackingOptions(sessions: sessions, appLifecycles: appLifecycles, screenViews: screenViews) + } + + return configuration } - public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - do { - if let args = try getPropertiesFromArguments(call.arguments) { - let instanceName = args["instanceName"] as! String - - switch (call.method) { - // Init - case "init": - let apiKey = args["apiKey"] as! String - - if (apiKey.isEmpty) { - result(FlutterError.init(code: "EMPTY_APP_KEY", - message: "Please initialize the Amplitude with a valid API Key.", details: nil)) - return - } - - if let userId = args["userId"] as? String { - Amplitude.instance(withName: instanceName).initializeApiKey(apiKey, userId: userId) - } - else { - Amplitude.instance(withName: instanceName).initializeApiKey(apiKey) - } - - result(true) - - // Get userId - case "getUserId": - result(Amplitude.instance(withName: instanceName).userId); - // Get deviceId - case "getDeviceId": - let deviceId = Amplitude.instance(withName: instanceName).getDeviceId() - result(deviceId) - // Get sessionId - case "getSessionId": - let sessionId = Amplitude.instance(withName: instanceName).getSessionId() - result(sessionId) - - // Setters - case "enableCoppaControl": - Amplitude.instance(withName: instanceName).enableCoppaControl(); - result(true) - case "disableCoppaControl": - Amplitude.instance(withName: instanceName).disableCoppaControl(); - result(true) - case "setOptOut": - let optOut = args["optOut"] as! Bool - Amplitude.instance(withName: instanceName).optOut = optOut - result(true) - case "setLibraryName": - let libraryName = args["libraryName"] as! String - Amplitude.instance(withName: instanceName).libraryName = libraryName - result(true) - case "setLibraryVersion": - let libraryVersion = args["libraryVersion"] as! String - Amplitude.instance(withName: instanceName).libraryVersion = libraryVersion - result(true) - case "setEventUploadThreshold": - let eventUploadThreshold = args["eventUploadThreshold"] as! Int32 - Amplitude.instance(withName: instanceName).eventUploadThreshold = eventUploadThreshold - result(true) - case "setEventUploadPeriodMillis": - let eventUploadPeriodMillis = args["eventUploadPeriodMillis"] as! Int32 - Amplitude.instance(withName: instanceName).eventUploadPeriodSeconds = eventUploadPeriodMillis / 1000 - result(true) - case "trackingSessionEvents": - let trackingSessionEvents = args["trackingSessionEvents"] as! Bool - Amplitude.instance(withName: instanceName).trackingSessionEvents = trackingSessionEvents - result(true) - case "setUseDynamicConfig": - let useDynamicConfig = args["useDynamicConfig"] as! Bool - Amplitude.instance(withName: instanceName).useDynamicConfig = useDynamicConfig - result(true) - case "setUserId": - var userId: String? = nil - if !(args["userId"] is NSNull) { - userId = args["userId"] as! String? - } - let startNewSession = args["startNewSession"] == nil ? false : (args["startNewSession"] as! Bool) - - Amplitude.instance(withName: instanceName).setUserId(userId, startNewSession: startNewSession) - result(true) - case "setDeviceId": - if !(args["deviceId"] is NSNull) { - if let deviceId = args["deviceId"] as! String? { - Amplitude.instance(withName: instanceName).setDeviceId(deviceId) - } - } - - result(true) - case "setServerUrl": - if !(args["serverUrl"] is NSNull) { - if let serverUrl = args["serverUrl"] as! String? { - Amplitude.instance(withName: instanceName).setServerUrl(serverUrl) - } - } - - result(true) - - // Regenerates a new random deviceId for current user - case "regenerateDeviceId": - Amplitude.instance(withName: instanceName).regenerateDeviceId() - result(true) - - // Event logging - case "logEvent": - let eventType = args["eventType"] as! String - let eventProperties = args["eventProperties"] as! [String: Any]? - let outOfSession = args["outOfSession"] == nil ? false : (args["outOfSession"] as! Bool) - - Amplitude.instance(withName: instanceName).logEvent(eventType, - withEventProperties: eventProperties, - outOfSession: outOfSession) - result(true) - case "logRevenue": - let revenue = AMPRevenue() - revenue.setProductIdentifier((args["productIdentifier"] as! String)) - revenue.setQuantity(args["quantity"] as! Int) - revenue.setPrice(NSNumber(value: args["price"] as! Double)) - - Amplitude.instance(withName: instanceName).logRevenueV2(revenue) - - result(true) - - case "logRevenueAmount": - let revenue = AMPRevenue() - revenue.setPrice(NSNumber(value: args["amount"] as! Double)) - Amplitude.instance(withName: instanceName).logRevenueV2(revenue) - - result(true) - - case "identify": - let userProperties = args["userProperties"] as! [String: [String : NSObject]] - let identify: AMPIdentify = createIdentify(userProperties) - Amplitude.instance(withName: instanceName).identify(identify) - result(true) - - case "setGroup": - let groupType = args["groupType"] as! String - let groupName = args["groupName"] as! NSObject - Amplitude.instance(withName: instanceName).setGroup(groupType, groupName: groupName) - - result(true) - case "groupIdentify": - let groupType = args["groupType"] as! String - let groupName = args["groupName"] as! NSObject - let userProperties = args["userProperties"] as! [String: [String : NSObject]] - let outOfSession = args["outOfSession"] == nil ? false : (args["outOfSession"] as! Bool) - let identify: AMPIdentify = createIdentify(userProperties) - Amplitude.instance(withName: instanceName).groupIdentify(withGroupType: groupType, - groupName: groupName, - groupIdentify: identify, - outOfSession: outOfSession) - result(true) - - // User properties - case "setUserProperties": - let userProperties = args["userProperties"] as! [String: Any]? ?? [:] - Amplitude.instance(withName: instanceName).setUserProperties(userProperties) - result(true) - case "clearUserProperties": - Amplitude.instance(withName: instanceName).clearUserProperties() - result(true) - - case "uploadEvents": - Amplitude.instance(withName: instanceName).uploadEvents() - result(true) - - // this method is for android only - case "useAppSetIdForDeviceId": - result(false) - - case "setMinTimeBetweenSessionsMillis": - let timeInMillis = args["timeInMillis"] as! Int - Amplitude.instance(withName: instanceName).minTimeBetweenSessionsMillis = timeInMillis - result(true) - - case "setServerZone": - let serverZone = args["serverZone"] as! String - let updateServerUrl = args["updateServerUrl"] as! Bool - let ampServerZone = serverZone == "EU" ? AMPServerZone.EU : AMPServerZone.US - Amplitude.instance(withName: instanceName).setServerZone(ampServerZone, updateServerUrl: updateServerUrl) - result(true) - - case "setOffline": - let offline = args["offline"] as! Bool - Amplitude.instance(withName: instanceName).setOffline(offline) - result(true) - - default: - result(FlutterMethodNotImplemented) - } - } - } catch { - result(FlutterError.init(code: "EXCEPTION_IN_HANDLE", - message: "Exception happened in handle.", details: nil)) + private func logLevelFromString(_ logLevelString: String) -> LogLevelEnum { + switch logLevelString.lowercased() { + case "off": + return .OFF + case "error": + return .ERROR + case "warn": + return .WARN + case "log": + return .LOG + case "debug": + return .DEBUG + default: + return .WARN } } - private func createIdentify(_ userProperties: [String: [String : NSObject]]) -> AMPIdentify { - let identify = AMPIdentify() - - for (operation, properties) in userProperties { - for (key, value) in properties { - switch operation { - case "$add": - identify.add(key, value: value) - case "$append": - identify.append(key, value: value) - case "$prepend": - identify.prepend(key, value: value) - case "$set": - identify.set(key, value: value) - case "$setOnce": - identify.setOnce(key, value: value) - case "$unset": - identify.unset(key) // value is default to `-` - case "$preInsert": - identify.preInsert(key, value: value) - case "$postInsert": - identify.postInsert(key, value: value) - case "$remove": - identify.remove(key, value: value) - case "$clearAll": - identify.clearAll() - default: - break - } - } + + private func convertMapToTrackingOptions(map: [String: Any]) -> TrackingOptions { + let trackingOptions = TrackingOptions() + + if let ipAddress = map["ipAddress"] as? Bool, !ipAddress { + trackingOptions.disableTrackIpAddress() + } + if let language = map["language"] as? Bool, !language { + trackingOptions.disableTrackLanguage() + } + if let platform = map["platform"] as? Bool, !platform { + trackingOptions.disableTrackPlatform() + } + if let region = map["region"] as? Bool, !region { + trackingOptions.disableTrackRegion() + } + if let dma = map["dma"] as? Bool, !dma { + trackingOptions.disableTrackDMA() + } + if let country = map["country"] as? Bool, !country { + trackingOptions.disableTrackCountry() + } + if let city = map["city"] as? Bool, !city { + trackingOptions.disableTrackCity() + } + if let carrier = map["carrier"] as? Bool, !carrier { + trackingOptions.disableTrackCarrier() + } + if let deviceModel = map["deviceModel"] as? Bool, !deviceModel { + trackingOptions.disableTrackDeviceModel() + } + if let deviceManufacturer = map["deviceManufacturer"] as? Bool, !deviceManufacturer { + trackingOptions.disableTrackDeviceManufacturer() + } + if let osVersion = map["osVersion"] as? Bool, !osVersion { + trackingOptions.disableTrackOsVersion() + } + if let osName = map["osName"] as? Bool, !osName { + trackingOptions.disableTrackOsName() + } + if let versionName = map["versionName"] as? Bool, !versionName { + trackingOptions.disableTrackVersionName() + } + if let idfv = map["idfv"] as? Bool, !idfv { + trackingOptions.disableTrackIDFV() + } + + return trackingOptions + } + + + private func getEvent(call: FlutterMethodCall) -> BaseEvent { + let args = call.arguments as! [String: Any] + let eventType = args["event_type"] as! String + + let event = BaseEvent(eventType: eventType) + + if let eventProperties = args["event_properties"] as? [String: Any] { + event.eventProperties = eventProperties + } + if let userProperties = args["user_properties"] as? [String: Any] { + event.userProperties = userProperties + } + if let groups = args["groups"] as? [String: Any] { + event.groups = groups + } + if let groupProperties = args["group_properties"] as? [String: Any] { + event.groupProperties = groupProperties + } + if let userId = args["user_id"] as? String { + event.userId = userId + } + if let deviceId = args["device_id"] as? String { + event.deviceId = deviceId + } + if let timestamp = args["timestamp"] as? Int { + event.timestamp = Int64(timestamp) + } + if let eventId = args["event_id"] as? Int { + event.eventId = Int64(eventId) + } + if let sessionId = args["session_id"] as? Int { + event.sessionId = Int64(sessionId) + } + if let insertId = args["insert_id"] as? String { + event.insertId = insertId + } + if let locationLat = args["location_lat"] as? Double { + event.locationLat = locationLat + } + if let locationLng = args["location_lng"] as? Double { + event.locationLng = locationLng } - return identify + if let planMap = args["plan"] as? [String: Any] { + event.plan = Plan(branch: planMap["branch"] as? String, source: planMap["source"] as? String, version: planMap["version"] as? String, versionId: planMap["versionId"] as? String) + } + if let ingestionMetadataMap = args["ingestion_metadata"] as? [String: Any] { + event.ingestionMetadata = IngestionMetadata(sourceName: ingestionMetadataMap["sourceName"] as? String, sourceVersion: ingestionMetadataMap["sourceVersion"] as? String) + } + if let revenue = args["revenue"] as? Double { + event.revenue = revenue + } + if let price = args["price"] as? Double { + event.price = price + } + if let quantity = args["quantity"] as? Int { + event.quantity = quantity + } + if let productId = args["product_id"] as? String { + event.productId = productId + } + if let revenueType = args["revenue_type"] as? String { + event.revenueType = revenueType + } + if let extra = args["extra"] as? [String: Any] { + event.extra = extra + } + if let partnerId = args["partner_id"] as? String { + event.partnerId = partnerId + } + + return event } + } diff --git a/ios/amplitude_flutter.podspec b/ios/amplitude_flutter.podspec index 5b5cadf..169a40b 100644 --- a/ios/amplitude_flutter.podspec +++ b/ios/amplitude_flutter.podspec @@ -12,8 +12,8 @@ Pod::Spec.new do |s| s.source_files = 'Classes/**/*' s.public_header_files = 'Classes/**/*.h' s.dependency 'Flutter' - s.dependency 'Amplitude', '8.16.1' + s.dependency 'AmplitudeSwift', '~> 1.0.0' - s.ios.deployment_target = '10.0' + s.ios.deployment_target = '13.0' end From d473c3e601b90fbb810313ba846b248100ba04e1 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Tue, 5 Mar 2024 16:21:00 -0800 Subject: [PATCH 02/11] set library --- ios/Classes/FlutterLibraryPlugin.swift | 18 ++++++++++++++++++ ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 8 +++++--- ios/amplitude_flutter.podspec | 5 ++++- release.config.js | 14 ++++++++++++++ 4 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 ios/Classes/FlutterLibraryPlugin.swift diff --git a/ios/Classes/FlutterLibraryPlugin.swift b/ios/Classes/FlutterLibraryPlugin.swift new file mode 100644 index 0000000..52524ef --- /dev/null +++ b/ios/Classes/FlutterLibraryPlugin.swift @@ -0,0 +1,18 @@ +import Foundation +import AmplitudeSwift + +class FlutterLibraryPlugin: BeforePlugin { + static let sdkLibrary = "amplitude-flutter" + // Version is managed automatically by semantic-release in release.config.js, please don't change it manually + static let sdkVersion = "4.0.0-beta.0" + + override func setup(amplitude: Amplitude) { + super.setup(amplitude: amplitude) + } + + override func execute(event: BaseEvent) -> BaseEvent? { + event.library = "\(FlutterLibraryPlugin.sdkLibrary)/\(FlutterLibraryPlugin.sdkVersion)" + + return event + } +} diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 967fc9c..1133a38 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -18,10 +18,12 @@ import AmplitudeSwift amplitude = Amplitude(configuration: getConfiguration(call: call)) - // TODO(xinyi): add library plugin + // Set library + amplitude?.add(plugin: FlutterLibraryPlugin()) + amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") - // TODO(xinyi): check app lifecycle events + // TODO(xinyi): add app lifecycle events result("init called..") @@ -171,7 +173,7 @@ import AmplitudeSwift case "debug": return .DEBUG default: - return .WARN + return .DEBUG } } diff --git a/ios/amplitude_flutter.podspec b/ios/amplitude_flutter.podspec index 169a40b..9888653 100644 --- a/ios/amplitude_flutter.podspec +++ b/ios/amplitude_flutter.podspec @@ -1,9 +1,12 @@ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # + +amplitude_version = "4.0.0-beta.0" # Version is managed automatically by semantic-release, please don't change it manually + Pod::Spec.new do |s| s.name = 'amplitude_flutter' - s.version = '0.0.1' + s.version = amplitude_version s.summary = 'A new flutter plugin project.' s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } diff --git a/release.config.js b/release.config.js index 7b5b234..03a5a8f 100644 --- a/release.config.js +++ b/release.config.js @@ -77,6 +77,20 @@ module.exports = { ], "countMatches": true }, + { + "files": ["ios/Classes/FlutterLibraryPlugin.swift"], + "from": "static let sdkVersion = \".*\"", + "to": "static let sdkVersion = \"${nextRelease.version}\"", + "results": [ + { + "file": "ios/Classes/FlutterLibraryPlugin.swift", + "hasChanged": true, + "numMatches": 1, + "numReplacements": 1 + } + ], + "countMatches": true + }, ] } ], From cda19e1897cd2010b37507b09f638b3283ece4f5 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Tue, 5 Mar 2024 17:35:56 -0800 Subject: [PATCH 03/11] swiftlint --- ios/Classes/FlutterLibraryPlugin.swift | 4 - ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 178 ++++++++++++------ 2 files changed, 121 insertions(+), 61 deletions(-) diff --git a/ios/Classes/FlutterLibraryPlugin.swift b/ios/Classes/FlutterLibraryPlugin.swift index 52524ef..18d3618 100644 --- a/ios/Classes/FlutterLibraryPlugin.swift +++ b/ios/Classes/FlutterLibraryPlugin.swift @@ -6,10 +6,6 @@ class FlutterLibraryPlugin: BeforePlugin { // Version is managed automatically by semantic-release in release.config.js, please don't change it manually static let sdkVersion = "4.0.0-beta.0" - override func setup(amplitude: Amplitude) { - super.setup(amplitude: amplitude) - } - override func execute(event: BaseEvent) -> BaseEvent? { event.library = "\(FlutterLibraryPlugin.sdkLibrary)/\(FlutterLibraryPlugin.sdkVersion)" diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 1133a38..892b997 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -2,7 +2,9 @@ import Flutter import UIKit import AmplitudeSwift +// swiftlint:disable type_body_length @objc public class SwiftAmplitudeFlutterPlugin: NSObject, FlutterPlugin { +// swiftlint:enable type_body_length var amplitude: Amplitude? static let methodChannelName = "amplitude_flutter" @@ -12,98 +14,140 @@ import AmplitudeSwift registrar.addMethodCallDelegate(instance, channel: channel) } + // swiftlint:disable cyclomatic_complexity + // swiftlint:disable function_body_length public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - switch call.method { - case "init": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + + switch call.method { + case "init": - amplitude = Amplitude(configuration: getConfiguration(call: call)) + do { + amplitude = Amplitude(configuration: try getConfiguration(args: args)) + } catch { + print("Initialization failed.") + } - // Set library - amplitude?.add(plugin: FlutterLibraryPlugin()) + // Set library + amplitude?.add(plugin: FlutterLibraryPlugin()) - amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") + amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") - // TODO(xinyi): add app lifecycle events + // swiftlint:disable todo + // TODO(xinyi): add app lifecycle events + // swiftlint:enable todo - result("init called..") + result("init called..") - case "track": - let event = getEvent(call: call) + case "track": + do { + let event = try getEvent(args: args) amplitude?.track(event: event) amplitude?.logger?.debug(message: "Track event: \(String(describing: call.arguments))") result("track called..") + } catch { + amplitude?.logger?.warn(message: "track called but failed.") + } - case "identify": - let event = getEvent(call: call) + case "identify": + do { + let event = try getEvent(args: args) amplitude?.track(event: event) amplitude?.logger?.debug(message: "Track identify event: \(String(describing: call.arguments))") result("identify called..") + } catch { + amplitude?.logger?.warn(message: "identify called but failed.") + } - case "groupIdentify": - let event = getEvent(call: call) + case "groupIdentify": + do { + let event = try getEvent(args: args) amplitude?.track(event: event) amplitude?.logger?.debug(message: "Track group identify event: \(String(describing: call.arguments))") result("groupIdentify called..") + } catch { + amplitude?.logger?.warn(message: "groupIdentify called but failed.") + } - case "setGroup": - let event = getEvent(call: call) + case "setGroup": + do { + let event = try getEvent(args: args) amplitude?.track(event: event) amplitude?.logger?.debug(message: "Track set group event: \(String(describing: call.arguments))") result("setGroup called..") + } catch { + amplitude?.logger?.warn(message: "setGroup called but failed.") + } - case "revenue": - let event = getEvent(call: call) + case "revenue": + do { + let event = try getEvent(args: args) amplitude?.track(event: event) amplitude?.logger?.debug(message: "Track revenue event: \(String(describing: call.arguments))") result("revenue called..") + } catch { + amplitude?.logger?.warn(message: "revenue called but failed.") + } - case "setUserId": - let args = call.arguments as! [String: String] - let userId = args["setUserId"] - amplitude?.setUserId(userId: userId) - amplitude?.logger?.debug(message: "Set user Id to \(String(describing: userId))") + case "setUserId": + guard let userId = args["setUserId"] as? String else { + amplitude?.logger?.warn(message: "setUserId type casting to String failed.") + return + } + amplitude?.setUserId(userId: userId) + amplitude?.logger?.debug(message: "Set user Id to \(String(describing: userId))") - result("serUserId called..") + result("serUserId called..") - case "setDeviceId": - let args = call.arguments as! [String: String] - let deviceId = args["setDeviceId"] - amplitude?.setDeviceId(deviceId: deviceId) - amplitude?.logger?.debug(message: "Set device Id to \(String(describing: deviceId))") + case "setDeviceId": + guard let deviceId = args["setDeviceId"] as? String else { + amplitude?.logger?.warn(message: "setDeviceId type casting to String failed.") + return + } + amplitude?.setDeviceId(deviceId: deviceId) + amplitude?.logger?.debug(message: "Set device Id to \(String(describing: deviceId))") - result("setDeviceId called..") + result("setDeviceId called..") - case "reset": - amplitude?.reset() - amplitude?.logger?.debug(message: "Reset userId and deviceId.") + case "reset": + amplitude?.reset() + amplitude?.logger?.debug(message: "Reset userId and deviceId.") - result("reset called..") + result("reset called..") - case "flush": - amplitude?.flush() - amplitude?.logger?.debug(message: "Flush events.") + case "flush": + amplitude?.flush() + amplitude?.logger?.debug(message: "Flush events.") - result("flush called..") + result("flush called..") - default: - amplitude?.logger?.debug(message: "Method \(call.method) is not recognized.") - result(FlutterMethodNotImplemented) - } + default: + amplitude?.logger?.debug(message: "Method \(call.method) is not recognized.") + result(FlutterMethodNotImplemented) } + } - private func getConfiguration(call: FlutterMethodCall) -> Configuration { - let args = call.arguments as! [String: Any] - let apiKey = args["apiKey"] as! String + private func getConfiguration(args: [String: Any]) throws -> Configuration { + guard let apiKey = args["apiKey"] as? String else { + print("apiKey type casting failed.") + throw AmplitudeFlutterPluginError.apiKeyNotFound + } - let instanceName = args["instanceName"] as! String - let migrateLegacyData = args["migrateLegacyData"] as! Bool + let instanceName = args["instanceName"] as? String ?? Constants.Configuration.DEFAULT_INSTANCE + let migrateLegacyData = args["migrateLegacyData"] as? Bool ?? true - let configuration = Configuration(apiKey: apiKey, instanceName: instanceName, migrateLegacyData: migrateLegacyData) + let configuration = Configuration( + apiKey: apiKey, + instanceName: instanceName, + migrateLegacyData: migrateLegacyData) if let flushQueueSize = args["flushQueueSize"] as? Int { configuration.flushQueueSize = flushQueueSize @@ -129,7 +173,8 @@ import AmplitudeSwift if let useBatch = args["useBatch"] as? Bool { configuration.useBatch = useBatch } - if let serverZone = args["serverZone"] as? String, let serverZoneValue = ServerZone(rawValue: serverZone.uppercased()) { + if let serverZone = args["serverZone"] as? String, let serverZoneValue = ServerZone( + rawValue: serverZone.uppercased()) { configuration.serverZone = serverZoneValue } if let serverUrl = args["serverUrl"] as? String { @@ -154,7 +199,11 @@ import AmplitudeSwift let sessions = defaultTrackingDict["sessions"] ?? true let appLifecycles = defaultTrackingDict["appLifecycles"] ?? false let screenViews = defaultTrackingDict["screenViews"] ?? false - configuration.defaultTracking = DefaultTrackingOptions(sessions: sessions, appLifecycles: appLifecycles, screenViews: screenViews) + configuration.defaultTracking = DefaultTrackingOptions( + sessions: sessions, + appLifecycles: appLifecycles, + screenViews: screenViews + ) } return configuration @@ -177,7 +226,6 @@ import AmplitudeSwift } } - private func convertMapToTrackingOptions(map: [String: Any]) -> TrackingOptions { let trackingOptions = TrackingOptions() @@ -227,10 +275,11 @@ import AmplitudeSwift return trackingOptions } - - private func getEvent(call: FlutterMethodCall) -> BaseEvent { - let args = call.arguments as! [String: Any] - let eventType = args["event_type"] as! String + private func getEvent(args: [String: Any]) throws -> BaseEvent { + guard let eventType = args["event_type"] as? String else { + amplitude?.logger?.warn(message: "eventType type casting failed.") + throw AmplitudeFlutterPluginError.eventTypeNotFound + } let event = BaseEvent(eventType: eventType) @@ -271,10 +320,18 @@ import AmplitudeSwift event.locationLng = locationLng } if let planMap = args["plan"] as? [String: Any] { - event.plan = Plan(branch: planMap["branch"] as? String, source: planMap["source"] as? String, version: planMap["version"] as? String, versionId: planMap["versionId"] as? String) + event.plan = Plan( + branch: planMap["branch"] as? String, + source: planMap["source"] as? String, + version: planMap["version"] as? String, + versionId: planMap["versionId"] as? String + ) } if let ingestionMetadataMap = args["ingestion_metadata"] as? [String: Any] { - event.ingestionMetadata = IngestionMetadata(sourceName: ingestionMetadataMap["sourceName"] as? String, sourceVersion: ingestionMetadataMap["sourceVersion"] as? String) + event.ingestionMetadata = IngestionMetadata( + sourceName: ingestionMetadataMap["sourceName"] as? String, + sourceVersion: ingestionMetadataMap["sourceVersion"] as? String + ) } if let revenue = args["revenue"] as? Double { event.revenue = revenue @@ -301,4 +358,11 @@ import AmplitudeSwift return event } + enum AmplitudeFlutterPluginError: Error { + case apiKeyNotFound + case eventTypeNotFound + } + + // swiftlint:enable cyclomatic_complexity + // swiftlint:enable function_body_length } From 0a7739065562d46044f1cd074193a177bdffe46e Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Tue, 5 Mar 2024 17:45:54 -0800 Subject: [PATCH 04/11] Update SwiftAmplitudeFlutterPlugin.swift --- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 44 ++++++++++++++++--- 1 file changed, 39 insertions(+), 5 deletions(-) diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 892b997..2fa4a37 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -17,13 +17,12 @@ import AmplitudeSwift // swiftlint:disable cyclomatic_complexity // swiftlint:disable function_body_length public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { - guard let args = call.arguments as? [String: Any] else { - print("\(call.method) called but call.arguments type casting failed.") - return - } - switch call.method { case "init": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } do { amplitude = Amplitude(configuration: try getConfiguration(args: args)) @@ -43,6 +42,11 @@ import AmplitudeSwift result("init called..") case "track": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + do { let event = try getEvent(args: args) amplitude?.track(event: event) @@ -54,6 +58,11 @@ import AmplitudeSwift } case "identify": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + do { let event = try getEvent(args: args) amplitude?.track(event: event) @@ -65,6 +74,11 @@ import AmplitudeSwift } case "groupIdentify": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + do { let event = try getEvent(args: args) amplitude?.track(event: event) @@ -76,6 +90,11 @@ import AmplitudeSwift } case "setGroup": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + do { let event = try getEvent(args: args) amplitude?.track(event: event) @@ -87,6 +106,11 @@ import AmplitudeSwift } case "revenue": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + do { let event = try getEvent(args: args) amplitude?.track(event: event) @@ -98,6 +122,11 @@ import AmplitudeSwift } case "setUserId": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + guard let userId = args["setUserId"] as? String else { amplitude?.logger?.warn(message: "setUserId type casting to String failed.") return @@ -108,6 +137,11 @@ import AmplitudeSwift result("serUserId called..") case "setDeviceId": + guard let args = call.arguments as? [String: Any] else { + print("\(call.method) called but call.arguments type casting failed.") + return + } + guard let deviceId = args["setDeviceId"] as? String else { amplitude?.logger?.warn(message: "setDeviceId type casting to String failed.") return From 5fb779600b4528f0bcad52b0a4d65186d4069fe1 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Tue, 5 Mar 2024 17:56:48 -0800 Subject: [PATCH 05/11] Update SwiftAmplitudeFlutterPlugin.swift --- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 2fa4a37..f21b584 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -141,7 +141,6 @@ import AmplitudeSwift print("\(call.method) called but call.arguments type casting failed.") return } - guard let deviceId = args["setDeviceId"] as? String else { amplitude?.logger?.warn(message: "setDeviceId type casting to String failed.") return @@ -396,7 +395,6 @@ import AmplitudeSwift case apiKeyNotFound case eventTypeNotFound } - // swiftlint:enable cyclomatic_complexity // swiftlint:enable function_body_length } From 6a4c481d6af2c35e6bcccf37ea89104325166309 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Tue, 5 Mar 2024 18:01:28 -0800 Subject: [PATCH 06/11] Create swift-lint.yml --- .github/workflows/swift-lint.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/swift-lint.yml diff --git a/.github/workflows/swift-lint.yml b/.github/workflows/swift-lint.yml new file mode 100644 index 0000000..a0c497a --- /dev/null +++ b/.github/workflows/swift-lint.yml @@ -0,0 +1,17 @@ +name: Swift Lint + +on: [pull_request] + +jobs: + lint: + runs-on: macos-12 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Set Xcode 14 + run: | + sudo xcode-select -switch /Applications/Xcode_14.1.app + + - name: Lint + run: cd ios && swiftlint --strict # force to fix warnings too From 6153514f6ad0ad0666b02661cab27f73b7dbbde9 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Wed, 6 Mar 2024 09:31:51 -0800 Subject: [PATCH 07/11] add missing fields --- .../AmplitudeFlutterPlugin.kt | 1 + ios/.swiftlint.yml | 21 ++++++ ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 65 ++++++++++++++++--- 3 files changed, 79 insertions(+), 8 deletions(-) create mode 100644 ios/.swiftlint.yml diff --git a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt index ad1590f..2a20845 100644 --- a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt +++ b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt @@ -196,6 +196,7 @@ class AmplitudeFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { call.argument("useBatch")?.let { configuration.useBatch = it } call.argument("serverZone") ?.let { configuration.serverZone = com.amplitude.core.ServerZone.valueOf(it.uppercase()) } + call.argument("serverUrl")?.let { configuration.serverUrl = it } call.argument("minTimeBetweenSessionsMillis") ?.let { configuration.minTimeBetweenSessionsMillis = it.toLong() } call.argument>("defaultTracking")?.let { map -> diff --git a/ios/.swiftlint.yml b/ios/.swiftlint.yml new file mode 100644 index 0000000..836179a --- /dev/null +++ b/ios/.swiftlint.yml @@ -0,0 +1,21 @@ +disabled_rules: + - file_length + - line_length + - function_body_length + - type_body_length + - trailing_comma + - opening_brace + - todo + - cyclomatic_complexity +identifier_name: + allowed_symbols: "_" + min_length: 1 +nesting: + type_level: + warning: 3 + error: 6 + function_level: + warning: 5 + error: 10 +excluded: + - Examples diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index f21b584..27d5cc8 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -2,9 +2,7 @@ import Flutter import UIKit import AmplitudeSwift -// swiftlint:disable type_body_length @objc public class SwiftAmplitudeFlutterPlugin: NSObject, FlutterPlugin { -// swiftlint:enable type_body_length var amplitude: Amplitude? static let methodChannelName = "amplitude_flutter" @@ -14,8 +12,6 @@ import AmplitudeSwift registrar.addMethodCallDelegate(instance, channel: channel) } - // swiftlint:disable cyclomatic_complexity - // swiftlint:disable function_body_length public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) { switch call.method { case "init": @@ -35,9 +31,7 @@ import AmplitudeSwift amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") - // swiftlint:disable todo // TODO(xinyi): add app lifecycle events - // swiftlint:enable todo result("init called..") @@ -352,6 +346,63 @@ import AmplitudeSwift if let locationLng = args["location_lng"] as? Double { event.locationLng = locationLng } + if let appVersion = args["app_version"] as? String { + event.appVersion = appVersion + } + if let versionName = args["version_name"] as? String { + event.versionName = versionName + } + if let platform = args["platform"] as? String { + event.platform = platform + } + if let osName = args["os_name"] as? String { + event.osName = osName + } + if let osVersion = args["os_version"] as? String { + event.osVersion = osVersion + } + if let deviceBrand = args["device_brand"] as? String { + event.deviceBrand = deviceBrand + } + if let deviceManufacturer = args["device_manufacturer"] as? String { + event.deviceManufacturer = deviceManufacturer + } + if let deviceModel = args["device_model"] as? String { + event.deviceModel = deviceModel + } + if let carrier = args["carrier"] as? String { + event.carrier = carrier + } + if let country = args["country"] as? String { + event.country = country + } + if let region = args["region"] as? String { + event.region = region + } + if let city = args["city"] as? String { + event.city = city + } + if let dma = args["dma"] as? String { + event.dma = dma + } + if let idfa = args["idfa"] as? String { + event.idfa = idfa + } + if let idfv = args["idfv"] as? String { + event.idfv = idfv + } + if let adid = args["adid"] as? String { + event.adid = adid + } + if let language = args["language"] as? String { + event.language = language + } + if let library = args["library"] as? String { + event.library = library + } + if let ip = args["ip"] as? String { + event.ip = ip + } if let planMap = args["plan"] as? [String: Any] { event.plan = Plan( branch: planMap["branch"] as? String, @@ -395,6 +446,4 @@ import AmplitudeSwift case apiKeyNotFound case eventTypeNotFound } - // swiftlint:enable cyclomatic_complexity - // swiftlint:enable function_body_length } From d0e5f078b78db6be343696b4de591d0cec2826d8 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Wed, 6 Mar 2024 09:43:34 -0800 Subject: [PATCH 08/11] consolidate switch cases --- .../AmplitudeFlutterPlugin.kt | 38 +--------- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 72 ++----------------- 2 files changed, 7 insertions(+), 103 deletions(-) diff --git a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt index 2a20845..c55f443 100644 --- a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt +++ b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt @@ -81,44 +81,12 @@ class AmplitudeFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { result.success("init called..") } - "track" -> { + "track", "identify", "groupIdentify", "setGroup", "revenue" -> { val event = getEvent(call) amplitude.track(event) - amplitude.logger.debug("Track event: ${call.arguments}") + amplitude.logger.debug("Track ${call.method} event: ${call.arguments}") - result.success("track called..") - } - - "identify" -> { - val event = getEvent(call) - amplitude.track(event) - amplitude.logger.debug("Track identify event: ${call.arguments}") - - result.success("identify called..") - } - - "groupIdentify" -> { - val event = getEvent(call) - amplitude.track(event) - amplitude.logger.debug("Track group identify event: ${call.arguments}") - - result.success("groupIdentify called..") - } - - "setGroup" -> { - val event = getEvent(call) - amplitude.track(event) - amplitude.logger.debug("Track set group event: ${call.arguments}") - - result.success("setGroup called..") - } - - "revenue" -> { - val event = getEvent(call) - amplitude.track(event) - amplitude.logger.debug("Track revenue event: ${call.arguments}") - - result.success("revenue called..") + result.success("${call.method} called..") } "setUserId" -> { diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 27d5cc8..536d7a5 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -35,7 +35,7 @@ import AmplitudeSwift result("init called..") - case "track": + case "track", "identify", "groupIdentify", "setGroup", "revenue": guard let args = call.arguments as? [String: Any] else { print("\(call.method) called but call.arguments type casting failed.") return @@ -44,75 +44,11 @@ import AmplitudeSwift do { let event = try getEvent(args: args) amplitude?.track(event: event) - amplitude?.logger?.debug(message: "Track event: \(String(describing: call.arguments))") + amplitude?.logger?.debug(message: "Track \(call.method) event: \(String(describing: call.arguments))") - result("track called..") + result("\(call.method) called..") } catch { - amplitude?.logger?.warn(message: "track called but failed.") - } - - case "identify": - guard let args = call.arguments as? [String: Any] else { - print("\(call.method) called but call.arguments type casting failed.") - return - } - - do { - let event = try getEvent(args: args) - amplitude?.track(event: event) - amplitude?.logger?.debug(message: "Track identify event: \(String(describing: call.arguments))") - - result("identify called..") - } catch { - amplitude?.logger?.warn(message: "identify called but failed.") - } - - case "groupIdentify": - guard let args = call.arguments as? [String: Any] else { - print("\(call.method) called but call.arguments type casting failed.") - return - } - - do { - let event = try getEvent(args: args) - amplitude?.track(event: event) - amplitude?.logger?.debug(message: "Track group identify event: \(String(describing: call.arguments))") - - result("groupIdentify called..") - } catch { - amplitude?.logger?.warn(message: "groupIdentify called but failed.") - } - - case "setGroup": - guard let args = call.arguments as? [String: Any] else { - print("\(call.method) called but call.arguments type casting failed.") - return - } - - do { - let event = try getEvent(args: args) - amplitude?.track(event: event) - amplitude?.logger?.debug(message: "Track set group event: \(String(describing: call.arguments))") - - result("setGroup called..") - } catch { - amplitude?.logger?.warn(message: "setGroup called but failed.") - } - - case "revenue": - guard let args = call.arguments as? [String: Any] else { - print("\(call.method) called but call.arguments type casting failed.") - return - } - - do { - let event = try getEvent(args: args) - amplitude?.track(event: event) - amplitude?.logger?.debug(message: "Track revenue event: \(String(describing: call.arguments))") - - result("revenue called..") - } catch { - amplitude?.logger?.warn(message: "revenue called but failed.") + amplitude?.logger?.warn(message: "\(call.method) called but failed.") } case "setUserId": From f7029acb36eb24e5dc357dc07fc2eeb786077cc2 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Wed, 6 Mar 2024 10:54:20 -0800 Subject: [PATCH 09/11] set library via method channel --- android/build.gradle | 9 ------ .../AmplitudeFlutterPlugin.kt | 3 +- .../amplitude_flutter/FlutterLibraryPlugin.kt | 10 ++----- ios/Classes/FlutterLibraryPlugin.swift | 10 ++++--- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 2 +- ios/amplitude_flutter.podspec | 5 +--- lib/configuration.dart | 3 ++ lib/constants.dart | 2 ++ release.config.js | 28 ------------------- test/amplitude_test.dart | 3 ++ 10 files changed, 19 insertions(+), 56 deletions(-) diff --git a/android/build.gradle b/android/build.gradle index 6619741..abcc973 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,16 +21,10 @@ rootProject.allprojects { } } -ext { - PUBLISH_VERSION = '4.0.0-beta.0' -} - apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - buildFeatures.buildConfig true - compileSdkVersion 34 // Condition for namespace compatibility in AGP 8 if (project.android.hasProperty("namespace")) { @@ -42,9 +36,6 @@ android { } defaultConfig { minSdkVersion 16 - - buildConfigField 'String', 'SDK_VERSION', "\"${PUBLISH_VERSION}\"" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" } lintOptions { diff --git a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt index c55f443..7eebba1 100644 --- a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt +++ b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt @@ -28,7 +28,6 @@ class AmplitudeFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { private lateinit var channel: MethodChannel - companion object { private const val methodChannelName = "amplitude_flutter" } @@ -66,7 +65,7 @@ class AmplitudeFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { amplitude = Amplitude(configuration) // Set library - amplitude.add(FlutterLibraryPlugin()) + amplitude.add(FlutterLibraryPlugin(call.argument("library")!!)) call.argument("logLevel")?.let { amplitude.logger.logMode = Logger.LogMode.valueOf(it.uppercase()) diff --git a/android/src/main/kotlin/com/amplitude/amplitude_flutter/FlutterLibraryPlugin.kt b/android/src/main/kotlin/com/amplitude/amplitude_flutter/FlutterLibraryPlugin.kt index 8f15a30..c5b853e 100644 --- a/android/src/main/kotlin/com/amplitude/amplitude_flutter/FlutterLibraryPlugin.kt +++ b/android/src/main/kotlin/com/amplitude/amplitude_flutter/FlutterLibraryPlugin.kt @@ -3,19 +3,13 @@ package com.amplitude.amplitude_flutter import com.amplitude.core.Amplitude import com.amplitude.core.events.BaseEvent import com.amplitude.core.platform.Plugin -import com.amplitude.amplitude_flutter.BuildConfig -class FlutterLibraryPlugin: Plugin { +class FlutterLibraryPlugin(val library: String): Plugin { override val type: Plugin.Type = Plugin.Type.Before override lateinit var amplitude: Amplitude - companion object { - const val SDK_LIBRARY = "amplitude-flutter" - const val SDK_VERSION = BuildConfig.SDK_VERSION - } - override fun execute(event: BaseEvent): BaseEvent? { - event.library = "$SDK_LIBRARY/$SDK_VERSION" + event.library = library return super.execute(event) } } diff --git a/ios/Classes/FlutterLibraryPlugin.swift b/ios/Classes/FlutterLibraryPlugin.swift index 18d3618..d505751 100644 --- a/ios/Classes/FlutterLibraryPlugin.swift +++ b/ios/Classes/FlutterLibraryPlugin.swift @@ -2,12 +2,14 @@ import Foundation import AmplitudeSwift class FlutterLibraryPlugin: BeforePlugin { - static let sdkLibrary = "amplitude-flutter" - // Version is managed automatically by semantic-release in release.config.js, please don't change it manually - static let sdkVersion = "4.0.0-beta.0" + let library: String + + init(library: String) { + self.library = library + } override func execute(event: BaseEvent) -> BaseEvent? { - event.library = "\(FlutterLibraryPlugin.sdkLibrary)/\(FlutterLibraryPlugin.sdkVersion)" + event.library = library return event } diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 536d7a5..8e1d5de 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -27,7 +27,7 @@ import AmplitudeSwift } // Set library - amplitude?.add(plugin: FlutterLibraryPlugin()) + amplitude?.add(plugin: FlutterLibraryPlugin(library: args["library"] as! String)) amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") diff --git a/ios/amplitude_flutter.podspec b/ios/amplitude_flutter.podspec index 9888653..169a40b 100644 --- a/ios/amplitude_flutter.podspec +++ b/ios/amplitude_flutter.podspec @@ -1,12 +1,9 @@ # # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html # - -amplitude_version = "4.0.0-beta.0" # Version is managed automatically by semantic-release, please don't change it manually - Pod::Spec.new do |s| s.name = 'amplitude_flutter' - s.version = amplitude_version + s.version = '0.0.1' s.summary = 'A new flutter plugin project.' s.homepage = 'http://example.com' s.license = { :file => '../LICENSE' } diff --git a/lib/configuration.dart b/lib/configuration.dart index ce89b9f..958c2f0 100644 --- a/lib/configuration.dart +++ b/lib/configuration.dart @@ -93,6 +93,9 @@ class Configuration { 'useAdvertisingIdForDeviceId': useAdvertisingIdForDeviceId, 'useAppSetIdForDeviceId': useAppSetIdForDeviceId, 'appVersion': appVersion, + // This field doesn't belong to Configuration + // Pass it for FlutterLibraryPlugin + 'library': "${Constants.packageName}/${Constants.packageVersion}" }; } } diff --git a/lib/constants.dart b/lib/constants.dart index a11aab5..bc9480e 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -1,4 +1,6 @@ class Constants { + static const packageName = "amplitude-flutter"; + static const packageVersion = "3.16.1"; static const identify_event = "\$identify"; static const group_identify_event = "\$groupidentify"; static const revenue_event = "revenue_amount"; diff --git a/release.config.js b/release.config.js index 03a5a8f..28bebf7 100644 --- a/release.config.js +++ b/release.config.js @@ -63,34 +63,6 @@ module.exports = { ], "countMatches": true }, - { - "files": ["android/build.gradle"], - "from": "PUBLISH_VERSION = \'.*\'", - "to": "PUBLISH_VERSION = \'${nextRelease.version}\'", - "results": [ - { - "file": "android/build.gradle", - "hasChanged": true, - "numMatches": 1, - "numReplacements": 1 - } - ], - "countMatches": true - }, - { - "files": ["ios/Classes/FlutterLibraryPlugin.swift"], - "from": "static let sdkVersion = \".*\"", - "to": "static let sdkVersion = \"${nextRelease.version}\"", - "results": [ - { - "file": "ios/Classes/FlutterLibraryPlugin.swift", - "hasChanged": true, - "numMatches": 1, - "numReplacements": 1 - } - ], - "countMatches": true - }, ] } ], diff --git a/test/amplitude_test.dart b/test/amplitude_test.dart index 34c7724..a089422 100644 --- a/test/amplitude_test.dart +++ b/test/amplitude_test.dart @@ -83,6 +83,9 @@ void main() { "useAdvertisingIdForDeviceId": false, "useAppSetIdForDeviceId": false, "appVersion": null, + // This field doesn't belong to Configuration + // Pass it for FlutterLibraryPlugin + "library": "${Constants.packageName}/${Constants.packageVersion}" }; final testEvent = BaseEvent(eventType: "testEvent"); final testEventMap = { From 596613d9ad44e58f65148a149fb62896fa139d3d Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Wed, 6 Mar 2024 11:04:00 -0800 Subject: [PATCH 10/11] lint --- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index 8e1d5de..df7ed5d 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -27,7 +27,11 @@ import AmplitudeSwift } // Set library - amplitude?.add(plugin: FlutterLibraryPlugin(library: args["library"] as! String)) + guard let library = args["library"] as? String else { + amplitude?.logger?.warn(message: "Failed to set library.") + return + } + amplitude?.add(plugin: FlutterLibraryPlugin(library: library)) amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.") From 4eb9b6fa273ba26d7fe7d69ce1cb29aac5e33037 Mon Sep 17 00:00:00 2001 From: Xinyi Ye Date: Wed, 6 Mar 2024 13:31:24 -0800 Subject: [PATCH 11/11] default library version to unknown --- .../amplitude_flutter/AmplitudeFlutterPlugin.kt | 6 +++++- ios/Classes/SwiftAmplitudeFlutterPlugin.swift | 10 +++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt index 7eebba1..81bf7a7 100644 --- a/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt +++ b/android/src/main/kotlin/com/amplitude/amplitude_flutter/AmplitudeFlutterPlugin.kt @@ -65,7 +65,11 @@ class AmplitudeFlutterPlugin : FlutterPlugin, MethodCallHandler, ActivityAware { amplitude = Amplitude(configuration) // Set library - amplitude.add(FlutterLibraryPlugin(call.argument("library")!!)) + amplitude.add( + FlutterLibraryPlugin( + call.argument("library") ?: "amplitude-flutter/unknown" + ) + ) call.argument("logLevel")?.let { amplitude.logger.logMode = Logger.LogMode.valueOf(it.uppercase()) diff --git a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift index df7ed5d..39abc1d 100644 --- a/ios/Classes/SwiftAmplitudeFlutterPlugin.swift +++ b/ios/Classes/SwiftAmplitudeFlutterPlugin.swift @@ -27,11 +27,11 @@ import AmplitudeSwift } // Set library - guard let library = args["library"] as? String else { - amplitude?.logger?.warn(message: "Failed to set library.") - return - } - amplitude?.add(plugin: FlutterLibraryPlugin(library: library)) + amplitude?.add( + plugin: FlutterLibraryPlugin( + library: args["library"] as? String ?? "amplitude-flutter/unknown" + ) + ) amplitude?.logger?.debug(message: "Amplitude has been successfully initialized.")