Skip to content

Commit

Permalink
RMET-2732 ::: Merge development with latest ecommerce features (#31)
Browse files Browse the repository at this point in the history
* RMET-2112 FB Analytics - Return user's response to App Tracking Transparency prompt (#22)

* fix: add function for requestTrackingAuthorization without promise

References: https://outsystemsrd.atlassian.net/browse/RMET-2112

* fix: fixing function structure

* test: testing with promise

* test: testing with only 1 export

* test: use module.exports

* refactor: remove commented lines

* chore: update changelog

References: https://outsystemsrd.atlassian.net/browse/RMET-2112

* refactor: use constant

* RMET-2441 :: raise firebase-core version (#24)

* feat: raise firebase core version

* chore(release): raise to version 5.0.0-OS10

* RMET-2729 ::: JavaScript ::: Log e-commerce events  (#26)

* feat: added logECommerceEvent javascript function

* chore: updates CHANGELOG.md

* feat: changed how ecommerce arguments are passed to the native side

* feat: Add E-Commerce Events Logging on iOS (#27)

Implement the logic required to perform e-commerce event logging. The implementation is similar to the already existing logEvent but without any parameter number constraints.

Before logging, and considering that the Firebase Analytics library doesn't return any kind of error in case of any issues with the data, the implementation performs the following steps:
#1 - Flat the Key-Value pair information to a JSON Object. This is done on both Event Parameters and Items.
#2 - Validate if the event parameters and items are correctly constructed. Both validations are done isolated, with errors being handled and returned in case of occurrence.
#3 - Validate the event parameters and items are valid according to the event name. This time, the validation is done altogether, with errors being handled and returned in case of occurrence.
#4 - Merge event parameters and items into a single JSON object to be sent to Analytics for logging purposes.

The implementation, since it's done using Swift, involves adding the Swift dependency to the `plugin.xml`.

References: https://outsystemsrd.atlassian.net/browse/RMET-2731

* fix: Adjust Validations (#29)

Remove the default `quantity` value as this is already assured by Firebase.
Fix the `item_list_id` and `item_list_name` as only the property set on the event parameters should be removed and not both always.
File rename to match the structure name.

References: https://outsystemsrd.atlassian.net/browse/RMET-2731

* RMET-2730 ::: Android :::  E-Commerce events (#28)

* feat: added ecommerce events first version

* fix: added removed hook

* fix: fixed bugs with happy paths

* feat: added KDoc

* fix: removed unecessry verification

* chore: updated CHANGELOG

* fix: applied changes suggested on the PR comments

* fix: added missing bridge file

* fix: applied proposed changes

* fix: fixed class name (#30)

* chore(release): bump version to 5.0.0-OS11

---------

Co-authored-by: Alexandre Jacinto <[email protected]>
Co-authored-by: Marta Carlos <[email protected]>
Co-authored-by: Ricardo Silva <[email protected]>
  • Loading branch information
4 people authored Jan 11, 2024
1 parent 24a3a85 commit 57a993c
Show file tree
Hide file tree
Showing 30 changed files with 1,072 additions and 10 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,17 @@ The changes documented here do not include those from the original repository.

## [Unreleased]

## 5.0.0-OS11

### 2023-12-22
- Feat: add new e-commerce logging method on Android (https://outsystemsrd.atlassian.net/browse/RMET-2730).

### 2023-12-18
- Feat: Implement e-commerce logging on iOS (https://outsystemsrd.atlassian.net/browse/RMET-2731).

### 2023-12-13
- Feat: add new e-commerce logging method (https://outsystemsrd.atlassian.net/browse/RMET-2729).

## 5.0.0-OS10

### 2023-08-11
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-firebase-analytics",
"version": "5.0.0-OS10",
"version": "5.0.0-OS11",
"description": "Cordova plugin for Firebase Analytics",
"cordova": {
"id": "cordova-plugin-firebase-analytics",
Expand Down
40 changes: 35 additions & 5 deletions plugin.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-firebase-analytics"
version="5.0.0-OS10">
version="5.0.0-OS11">

<name>FirebaseAnalyticsPlugin</name>
<description>Cordova plugin for Firebase Analytics</description>
Expand Down Expand Up @@ -38,6 +38,8 @@ xmlns:android="http://schemas.android.com/apk/res/android"
</feature>
</config-file>

<dependency id="cordova-plugin-add-swift-support" url="https://github.com/OutSystems/cordova-plugin-add-swift-support.git#2.0.3-OS1"/>

<!--
use a bit hacky method to set boolean value as a string:
https://developer.apple.com/documentation/foundation/nsstring/1409420-boolvalue?preferredLanguage=occ
Expand All @@ -55,6 +57,23 @@ xmlns:android="http://schemas.android.com/apk/res/android"
<header-file src="src/ios/FirebaseAnalyticsPlugin.h" />
<source-file src="src/ios/FirebaseAnalyticsPlugin.m" />

<source-file src="src/ios/Common/Extensions/StringConvertable.swift" target-dir="Common/Extensions" />
<source-file src="src/ios/Common/OSFANLDefaultValues.swift" target-dir="Common" />
<source-file src="src/ios/Common/OSFANLError.swift" target-dir="Common" />
<source-file src="src/ios/Common/OSFANLInputDataFieldKey.swift" target-dir="Common" />

<source-file src="src/ios/InputTransformer/OSFANLInputTransformable.swift" target-dir="InputTransformer" />
<source-file src="src/ios/InputTransformer/OSFANLInputTransformableModel.swift" target-dir="InputTransformer" />
<source-file src="src/ios/InputTransformer/OSFANLInputTransformer.swift" target-dir="InputTransformer" />

<source-file src="src/ios/Manager/OSFANLManageable.swift" target-dir="Manager" />
<source-file src="src/ios/Manager/OSFANLManager.swift" target-dir="Manager" />
<source-file src="src/ios/Manager/OSFANLManager+EventValidationRules.swift" target-dir="Manager" />
<source-file src="src/ios/Manager/OSFANLManagerFactory.swift" target-dir="Manager" />
<source-file src="src/ios/Manager/OSFANLOutputModel.swift" target-dir="Manager" />

<source-file src="src/ios/Validator/OSFANLEventValidator.swift" target-dir="Validator" />

<podspec>
<config>
<source url="https://cdn.cocoapods.org/"/>
Expand All @@ -69,11 +88,10 @@ xmlns:android="http://schemas.android.com/apk/res/android"
<platform name="android">
<preference name="ANDROID_FIREBASE_ANALYTICS_VERSION" default="21.1.1"/>

<hook type="before_plugin_install" src="hooks/android/build_gradle_add_dependency.js" />

<config-file target="res/xml/config.xml" parent="/*">
<feature name="FirebaseAnalytics">
<param name="android-package" value="by.chemerisuk.cordova.firebase.FirebaseAnalyticsPlugin" />
<param name="android-package" value="com.outsystems.plugins.firebase.analytics.FirebaseAnalyticsPlugin" />
<param name="onload" value="$ANALYTICS_COLLECTION_ENABLED" />
</feature>
</config-file>
Expand All @@ -92,8 +110,20 @@ xmlns:android="http://schemas.android.com/apk/res/android"
<framework src="com.google.firebase:firebase-analytics:$ANDROID_FIREBASE_ANALYTICS_VERSION" />
<framework src="build.gradle" custom="true" type="gradleReference" />

<source-file src="src/android/FirebaseAnalyticsPlugin.java"
target-dir="src/by/chemerisuk/cordova/firebase/" />
<source-file src="src/android/com/outsystems/firebase/analytics/FirebaseAnalyticsPlugin.java" target-dir="src/com/outsystems/plugins/firebase/analytics/" />
<source-file src="src/android/com/outsystems/firebase/analytics/model/OSFANLBundle+putAny.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/model/" />
<source-file src="src/android/com/outsystems/firebase/analytics/model/OSFANLJSONArray+extension.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/model/" />
<source-file src="src/android/com/outsystems/firebase/analytics/model/OSFANLDefaultValues.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/model/" />
<source-file src="src/android/com/outsystems/firebase/analytics/model/OSFANLError.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/model/" />
<source-file src="src/android/com/outsystems/firebase/analytics/model/OSFANLEventOutputModel.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/model/" />
<source-file src="src/android/com/outsystems/firebase/analytics/model/OSFANLInputDataFieldKey.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/model/" />

<source-file src="src/android/com/outsystems/firebase/analytics/validator/OSFANLEventItemsValidator.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/validator/" />
<source-file src="src/android/com/outsystems/firebase/analytics/validator/OSFANLEventParameterValidator.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/validator/" />
<source-file src="src/android/com/outsystems/firebase/analytics/validator/OSFANLMinimumRequired.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/validator/" />

<source-file src="src/android/com/outsystems/firebase/analytics/OSFANLManager.kt" target-dir="app/src/main/kotlin/com/outsystems/firebase/analytics/" />

</platform>

</plugin>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package by.chemerisuk.cordova.firebase;
package com.outsystems.plugins.firebase.analytics;

import android.content.Context;
import android.os.Bundle;
Expand All @@ -8,6 +8,9 @@
import by.chemerisuk.cordova.support.ReflectiveCordovaPlugin;

import com.google.firebase.analytics.FirebaseAnalytics;
import com.outsystems.firebase.analytics.OSFANLManager;
import com.outsystems.firebase.analytics.model.OSFANLError;
import com.outsystems.firebase.analytics.model.OSFANLEventOutputModel;

import org.apache.cordova.CallbackContext;
import org.json.JSONException;
Expand All @@ -21,19 +24,18 @@ public class FirebaseAnalyticsPlugin extends ReflectiveCordovaPlugin {

private FirebaseAnalytics firebaseAnalytics;

private OSFANLManager manager = new OSFANLManager();

@Override
protected void pluginInitialize() {
Log.d(TAG, "Starting Firebase Analytics plugin");

Context context = this.cordova.getActivity().getApplicationContext();

this.firebaseAnalytics = FirebaseAnalytics.getInstance(context);
}

@CordovaMethod
private void logEvent(String name, JSONObject params, CallbackContext callbackContext) throws JSONException {
this.firebaseAnalytics.logEvent(name, parse(params));

callbackContext.success();
}

Expand Down Expand Up @@ -87,6 +89,20 @@ private void requestTrackingAuthorization(JSONObject params, CallbackContext cal
callbackContext.success();
}

@CordovaMethod
private void logECommerceEvent(JSONObject params, CallbackContext callbackContext) throws JSONException {
try {
OSFANLEventOutputModel output = manager.buildOutputEventFromInputJSON(params);
this.firebaseAnalytics.logEvent(output.getName(), output.getParameters());
callbackContext.success();
} catch (OSFANLError e) {
JSONObject result = new JSONObject();
result.put("code", e.getCode());
result.put("message", e.getMessage());
callbackContext.error(result);
}
}

private static Bundle parse(JSONObject params) throws JSONException {
Bundle bundle = new Bundle();
Iterator<String> it = params.keys();
Expand Down
160 changes: 160 additions & 0 deletions src/android/com/outsystems/firebase/analytics/OSFANLManager.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
package com.outsystems.firebase.analytics

import android.os.Bundle
import com.google.firebase.analytics.FirebaseAnalytics
import com.outsystems.firebase.analytics.model.OSFANLError
import com.outsystems.firebase.analytics.model.OSFANLEventOutputModel
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey.EVENT
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey.ITEMS
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey.SHIPPING
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey.TAX
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey.TRANSACTION_ID
import com.outsystems.firebase.analytics.model.OSFANLInputDataFieldKey.VALUE
import com.outsystems.firebase.analytics.model.getArrayOrEmpty
import com.outsystems.firebase.analytics.model.getStringOrNull
import com.outsystems.firebase.analytics.validator.OSFANLEventItemsValidator
import com.outsystems.firebase.analytics.validator.OSFANLEventParameterValidator
import com.outsystems.firebase.analytics.validator.OSFANLMinimumRequired.AT_LEAST_ONE
import com.outsystems.firebase.analytics.validator.OSFANLMinimumRequired.ONE
import org.json.JSONArray
import org.json.JSONObject
import java.io.Serializable

class OSFANLManager {

@Throws(OSFANLError::class)
fun buildOutputEventFromInputJSON(input: JSONObject): OSFANLEventOutputModel {

val eventName = input.getStringOrNull(OSFANLInputDataFieldKey.EVENT.json) ?: throw OSFANLError.missing(EVENT.json)
val parameters = input.getArrayOrEmpty(OSFANLInputDataFieldKey.EVENT_PARAMETERS.json)
val items = input.getArrayOrEmpty(ITEMS.json)

val eventBuilderMethod = getEventBuilderMethod(eventName)
val eventBundle = eventBuilderMethod(this, parameters, items)

return OSFANLEventOutputModel(eventName, eventBundle)
}

private fun getEventBuilderMethod(
eventName: String
): (OSFANLManager, JSONArray, JSONArray) -> Bundle {

when (eventName) {

FirebaseAnalytics.Event.PURCHASE ->
return OSFANLManager::buildBundleForPurchaseParametersEventType

FirebaseAnalytics.Event.REFUND ->
return OSFANLManager::buildBundleForRefundParametersEventType

FirebaseAnalytics.Event.SELECT_ITEM ->
return OSFANLManager::buildBundleForOneItemParametersEventType

FirebaseAnalytics.Event.SELECT_PROMOTION ->
return OSFANLManager::buildBundleForSelectPromotionParametersEventType

FirebaseAnalytics.Event.VIEW_ITEM_LIST ->
return OSFANLManager::buildBundleForViewItemListParametersEventType

FirebaseAnalytics.Event.VIEW_PROMOTION ->
return OSFANLManager::buildBundleForOneItemParametersEventType

else ->
return OSFANLManager::buildBundleForValueCurrencyAndMultipleItemsEventType
}
}

private fun buildBundleForValueCurrencyAndMultipleItemsEventType(
parameters: JSONArray,
items: JSONArray
): Bundle {
return buildAndValidateParameterBundle(
parameters,
items,
OSFANLEventParameterValidator.Builder()
.requireCurrencyValue()
.build(),
OSFANLEventItemsValidator(minLimit = AT_LEAST_ONE)
)
}

private fun buildBundleForPurchaseParametersEventType(
parameters: JSONArray,
items: JSONArray
): Bundle {
return buildAndValidateParameterBundle(
parameters,
items,
OSFANLEventParameterValidator.Builder()
.requireCurrencyValue()
.required(TRANSACTION_ID)
.number(SHIPPING, TAX)
.build(),
OSFANLEventItemsValidator(minLimit = AT_LEAST_ONE)
)
}

private fun buildBundleForRefundParametersEventType(
parameters: JSONArray,
items: JSONArray
): Bundle {
return buildAndValidateParameterBundle(
parameters,
items,
OSFANLEventParameterValidator.Builder()
.requireCurrencyValue()
.required(TRANSACTION_ID)
.number(SHIPPING, TAX)
.build()
)
}

private fun buildBundleForOneItemParametersEventType(
parameters: JSONArray,
items: JSONArray
): Bundle {
return buildAndValidateParameterBundle(
parameters,
items,
itemsValidator = OSFANLEventItemsValidator(minLimit = ONE)
)
}

private fun buildBundleForSelectPromotionParametersEventType(
parameters: JSONArray,
items: JSONArray
): Bundle {
return buildAndValidateParameterBundle(parameters, items)
}

private fun buildBundleForViewItemListParametersEventType(
parameters: JSONArray,
items: JSONArray
): Bundle {
return buildAndValidateParameterBundle(
parameters,
items,
itemsValidator = OSFANLEventItemsValidator(minLimit = AT_LEAST_ONE)
)
}

private fun buildAndValidateParameterBundle(
parameters: JSONArray,
items: JSONArray,
parametersValidator: OSFANLEventParameterValidator = OSFANLEventParameterValidator.Builder().build(),
itemsValidator: OSFANLEventItemsValidator = OSFANLEventItemsValidator()
): Bundle {

// validate parameters
val parameterBundle = parametersValidator.validate(parameters)

// validate items
val itemsBundle = itemsValidator.validate(items)
if(itemsBundle.isNotEmpty())
parameterBundle.putSerializable(ITEMS.json, itemsBundle as Serializable)

return parameterBundle
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.outsystems.firebase.analytics.model

import android.os.Bundle

/**
* Adds a range of different types to a bundle. Accepted types are String, Int, Double and Long
* @param key the key in which to store the value
* @param value the value to store
*/
fun Bundle.putAny(key: String, value: Any) {
when (value) {
is String -> this.putString(key, value)
is Int -> this.putInt(key, value)
is Double -> this.putDouble(key, value)
is Long -> this.putLong(key, value)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.outsystems.firebase.analytics.model

/**
* Holds the default size values for the input data
*/
class OSFANLDefaultValues {
companion object {
const val itemQuantity: Int = 1
const val itemCustomParametersMaximum: Int = 27
const val eventItemsMaximum: Int = 200
}
}
Loading

0 comments on commit 57a993c

Please sign in to comment.