Skip to content

hathway/mparticle-capacitor

Repository files navigation

mparticle-capacitor

mParticle Capacitor Plugin

Install

npm install npm i @hathway/mparticle-capacitor
npx cap sync

Initialize

Web (Angular)

Use mParticleConfig to create a configuration object used to initialize mParticle.

app.component.ts in ngOnInit()

import {MParticleCapacitor} from 'mparticle-capacitor';
...
    let mParticleKey = "YOUR KEY"
    MParticleCapacitor.mParticleConfig({
        isDevelopmentMode: true, 
        planID: "PLAN NAME", 
        planVer: 2,
        logLevel: "verbose", // || "warning" || "none"
    }).then((config:any) => {        
        if (!this.platform.is('hybrid')) {
            // add web kits here i.e.:
            // mParticleBraze.register(config);
        }
        MParticleCapacitor.mParticleInit({key: mParticleKey, mParticleConfig: config})
        .catch((e:any) => {}); // initialize mparticle web, catch when ios/android return unimplemented.  
    }).catch((e:any) => {});

    /* or */

    if (!this.platform.is('hybrid')) { initMP(); }

    async initMP() {
        let mParticleKey = "YOUR KEY"
        let mpConfig = await MParticleCapacitor.mParticleConfig({
            isDevelopmentMode: true, 
            planID: "PLAN NAME", 
            planVer: 2,
            logLevel: "verbose", // || "warning" || "none"
        });
        // add web kits here i.e.:
        // mParticleBraze.register(mpConfig);
        MParticleCapacitor.mParticleInit({key: mParticleKey, mParticleConfig: mpConfig});
    }

Android

Initilize mParticle in the app directly instead of the plugin, Appboy/Braze needs the permissions mParticle will pass to it through this. MainActivity.java in onCreate()

import com.mparticle.MParticle;
import com.mparticle.MParticleOptions;
...
public class MainActivity extends BridgeActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        MParticleOptions options = MParticleOptions.builder(this)
        .credentials( "YOUR KEY HERE", "MATCHING SECRET" )
        .environment(MParticle.Environment.Development) // or MParticle.Environment.Production
        .dataplan("master_data_plan", 2)
        .logLevel(MParticle.LogLevel.DEBUG) // to see debug logging in Android Studio
        .androidIdEnabled(true) // required for SDK 5.35+
        .build();
        MParticle.start(options);
    }
}

can't find "com.mparticle...."? add android:exported="true" to AndroidMnifest.xml under <activity>>

iOS

Initilize mParticle in the app directly instead of the plugin, Appboy/Braze needs the permissions mParticle will pass to it through this. AppDelegate.swift

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let options = MParticleOptions(key: "YOUR KEY HERE", secret: "MATCHING SECRET")
    options.environment = MPEnvironment.development; // or MPEnvironment.production
    options.dataPlanId = "master_data_plan"
    options.logLevel = MPILogLevel.verbose // to see debug logging in XCode
    MParticle.sharedInstance().start(with: options)
    return true
}

Adding Kits

All available kits can be found here: https://github.com/mparticle-integrations

MParticle provides a "black-box" solution to data sharing between other api. Kits do not need to be added to the plugin, they can be added directly to your app's Podfile (iOS) or build.gradle (Android) or into your app.component.ts (web).

Any Web Integration

Web kits are added before the web initialization in the component. If there is an error with the inport: Error: export 'MParticleBraze' (imported as 'MParticleBraze') was not found... import using require:

const mParticleBraze = require('@mparticle/web-braze-kit');

Braze Integration

mParticle will handle the integration internally as long as things are hooked up in the dashboard.

There are some custom settings and inclusions that need to be included in your project for mParticle to route data to Braze properly.

Android

Android will complain about not finding a package unless you include this repo in your build.gradle:

repositories {
    maven { url "https://appboy.github.io/appboy-android-sdk/sdk" }
    ...
}
dependencies {
    implementation 'com.mparticle:android-appboy-kit:5+'
}

Full documentation here: https://github.com/mparticle-integrations/mparticle-android-integration-appboy

iOS

Add the kit to your app's Podfile:

pod 'mParticle-Appboy', '~> 8'

Enable Push Notifications

Android

Add Firebase to your build.gradle

compile 'com.google.firebase:firebase-core:<YOUR_PLAY_SERVICES_VERSION>'
compile 'com.google.firebase:firebase-messaging:<YOUR_PLAY_SERVICES_VERSION>'

Add mParticle's InstanceService to AndroidManifest.xml

<service android:name="com.mparticle.messaging.InstanceIdService" />

<receiver
    android:name="com.mparticle.MPReceiver"
    android:permission="com.google.android.c2dm.permission.SEND">
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />

        <!-- Use your package name as the category -->
        <category android:name="YOURPACKAGENAME" />
    </intent-filter>
</receiver>
<!-- This is the service that does the heavy lifting in parsing, showing, and tracking FCM/GCM notifications. -->
<service android:name="com.mparticle.MPService" />

Add this to your MainActivity.java after your mParticle init

MParticle.getInstance().Messaging().enablePushNotifications( "YOUR SENDER ID" );

Full mParticle Documentation Here: https://docs.mparticle.com/developers/sdk/android/push-notifications/

Add BrazeFirebaseMessagingService to your AndroidManifest.xml

<service android:name="com.braze.push.BrazeFirebaseMessagingService" android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Create a braze.xml file in android/app/src/main/res/values

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <color name="com_braze_default_notification_accent_color">@android:color/black</color> <!--Sets Icon Background Default-->
  <drawable name="com_braze_push_small_notification_icon">@drawable/ic_star_face_larger_notification</drawable> <!--Sets Default Large Icon-->
  <drawable name="com_braze_push_large_notification_icon">@drawable/ic_star_vector</drawable> <!--Sets Default Small Icon-->
  <bool name="com_braze_handle_push_deep_links_automatically">true</bool> <!--Required to allow notification to open app-->
</resources>

Full Documentation Here: https://www.braze.com/docs/developer_guide/platform_integration_guides/android/push_notifications/android/integration/standard_integration/#custom-handling-for-push-receipts-opens-dismissals-and-key-value-pairs

iOS

mParticle will handle the integration internaly. There may be issues depending on other packages in your app. Full mParticle documentation here: https://docs.mparticle.com/developers/sdk/ios/push-notifications/

iOS does not pass push tokens automatically, for your hybrid app I recommend using: https://capacitorjs.com/docs/apis/push-notifications to request and enable push notifictaions for your users

Device Push Tokens Aren't Getting to Braze (swizzling)

Look for functions that override or proxy the AppDelegate functions specifically didRegisterForRemoteNotificationsWithDeviceToken. Firebase Gets in the way of Braze And mParticle interactions

ref: https://firebase.google.com/docs/cloud-messaging/ios/client The FCM SDK performs method swizzling in two key areas: mapping your APNs token to the FCM registration token and capturing analytics data during downstream message callback handling. Developers who prefer not to use swizzling can disable it by adding the flag FirebaseAppDelegateProxyEnabled in the app’s Info.plist file and setting it to NO (boolean value). Relevant areas of the guides provide code examples, both with and without method swizzling enabled.

solution is in your Info.plist: info.plist firebase

(via. https://firebase.google.com/docs/cloud-messaging/ios/client)

AppsFlyer

AppsFlyer works as expected out of the box. Most of the settings will be handled between the dashboards.

Android

Add the AppsFlyer kit to your app's build.gradle:

dependencies {
    implementation 'com.mparticle:android-appsflyer-kit:5+'
}

Full documentation here: https://github.com/mparticle-integrations/mparticle-android-integration-appsflyer

iOS

Add the kit to your app's Podfile:

pod 'mParticle-AppsFlyer', '~> 8'

Full documentation here: https://github.com/mparticle-integrations/mparticle-apple-integration-appsflyer

AppsFlyer Capacitor Plugin (Deeplining)

The AppsFlyer capacitor plugin can work in parallell with the kit to process the deeplinks

npm install appsflyer-capacitor-plugin  
npx cap sync

Note that we add the listener before the init.

AppsFlyer.addListener(AFConstants.UDL_CALLBACK, (res) => {
  console.log('URL APPSFLYER UDL_CALLBACK ~~>' + JSON.stringify(res));
  if (res.status === 'FOUND') {
    // do the deeplink process
  } else if (res.status === 'ERROR') {
    console.log('deep link error');
  } else {
    console.log('deep link not found');
  }
}); 

AppsFlyer.initSDK({
    appID: '{APPID}',  // replace with your app ID.
      devKey: '{DEVKEY}',   // replace with your dev key.
      isDebug: true,
      waitForATTUserAuthorization: 10, // for iOS 14 and higher
      registerOnDeepLink: true,
      registerConversionListener: true,
}).then().catch(e =>console.log("AppsFlyer Error Catch",e));    

It is also recommended to encapulate the above code in if (platform.is('hybrid')) { or something similar as this listener will throw an 'unimplemented' error when in a web environment. AppsFlyer documentation also recommends to start in this.platform.ready().then(() => {.

Full documentation here: https://github.com/AppsFlyerSDK/appsflyer-capacitor-plugin

API

echo(...)

echo(options: { value: string; }) => Promise<{ value: string; }>
Param Type
options { value: string; }

Returns: Promise<{ value: string; }>


mParticleConfig(...)

mParticleConfig(call: MParticleConfigArguments) => Promise<MPConfigType>
Param Type
call MParticleConfigArguments

Returns: Promise<MPConfigType>


mParticleInit(...)

mParticleInit(call: { key: string; mParticleConfig: any; }) => Promise<IdentityResult>
Param Type
call { key: string; mParticleConfig: any; }

Returns: Promise<IdentityResult>


loginMParticleUser(...)

loginMParticleUser(call: { email: string; customerId?: string; }) => Promise<{ value: string; }>
Param Type
call { email: string; customerId?: string; }

Returns: Promise<{ value: string; }>


logoutMParticleUser(...)

logoutMParticleUser(call?: any) => Promise<mParticle.IdentityResult>
Param Type
call any

Returns: Promise<IdentityResult>


getAllUserAttributes(...)

getAllUserAttributes(call?: any) => AllUserAttributes
Param Type
call any

Returns: AllUserAttributes


logMParticleEvent(...)

logMParticleEvent(call: { eventName: string; eventType: any; eventProperties: any; }) => void
Param Type
call { eventName: string; eventType: any; eventProperties: any; }

logMParticlePageView(...)

logMParticlePageView(call: { pageName: string; pageLink: any; overrides?: any; }) => void
Param Type
call { pageName: string; pageLink: any; overrides?: any; }

setUserAttribute(...)

setUserAttribute(call: { attributeName: string; attributeValue: string; }) => void
Param Type
call { attributeName: string; attributeValue: string; }

setUserAttributeList(...)

setUserAttributeList(call: { attributeName: string; attributeValues: any; }) => void
Param Type
call { attributeName: string; attributeValues: any; }

removeUserAttribute(...)

removeUserAttribute(call: { attributeName: string; }) => void
Param Type
call { attributeName: string; }

updateMParticleCart(...)

updateMParticleCart(call: { productData: any; customAttributes: any; eventType: any; }) => void
Param Type
call { productData: any; customAttributes: any; eventType: any; }

addMParticleProduct(...)

addMParticleProduct(call: { productData: any; customAttributes: any; }) => void
Param Type
call { productData: any; customAttributes: any; }

removeMParticleProduct(...)

removeMParticleProduct(call: { productData: any; customAttributes: any; }) => void
Param Type
call { productData: any; customAttributes: any; }

submitPurchaseEvent(...)

submitPurchaseEvent(call: { productData: any; customAttributes: any; transactionAttributes: any; }) => void
Param Type
call { productData: any; customAttributes: any; transactionAttributes: any; }

registerMParticleUser(...)

registerMParticleUser(call: { email: string; customerId?: string; userAttributes: any; }) => Promise<any>
Param Type
call { email: string; customerId?: string; userAttributes: any; }

Returns: Promise<any>


Interfaces

IdentityResult

Prop Type
httpCode any
body IdentityResultBody
Method Signature
getPreviousUser () => User
getUser () => User

User

Prop Type
getUserIdentities () => IdentityApiData
getMPID () => string
setUserTag (tag: string) => void
removeUserTag (tag: string) => void
setUserAttribute (key: string, value: string) => void
setUserAttributes (attributeObject: Record<string, unknown>) => void
removeUserAttribute (key: string) => void
setUserAttributeList (key: string, value: UserAttributesValue[]) => void
removeAllUserAttributes () => void
getUserAttributesLists () => Record<string, UserAttributesValue[]>
getAllUserAttributes () => AllUserAttributes
getCart () => Cart
getConsentState () => ConsentState
setConsentState (ConsentState: ConsentState) => void
isLoggedIn () => boolean
getLastSeenTime () => number
getFirstSeenTime () => number

IdentityApiData

Prop Type
userIdentities UserIdentities

UserIdentities

Prop Type
customerid string
email string
other string
other2 string
other3 string
other4 string
other5 string
other6 string
other7 string
other8 string
other9 string
other10 string
mobile_number string
phone_number_2 string
phone_number_3 string
facebook string
facebookcustomaudienceid string
google string
twitter string
microsoft string
yahoo string

Cart

Prop Type
add (product: Product, logEventBoolean?: boolean) => void
remove (product: Product, logEventBoolean?: boolean) => void
clear () => void

Product

Prop Type
id string
name string
brand string
category string
variant string
position number
price number
quantity number
coupon_code string
added_to_cart_time_ms number
total_product_amount number
custom_attributes { [key: string]: string; }

ConsentState

Prop Type
gdpr { [key: string]: GDPRConsentState; }
ccpa { data_sale_opt_out: CCPAConsentState; }

GDPRConsentState

Prop Type
purpose string
document string
consented boolean
timestamp_unixtime_ms number
location string
hardware_id string

PrivacyConsentState

Prop Type
Consented boolean
Timestamp number
ConsentDocument string
Location string
HardwareId string

IdentityResultBody

Prop Type
context string | null
is_ephemeral boolean
is_logged_in boolean
matched_identities Record<string, unknown>

MParticleConfigArguments

Prop Type
isDevelopmentMode boolean
planID string
planVer number
planVersionRequired boolean
logLevel string
identifyRequest any
identityCallback ((i: IdentityResult) => void)

Type Aliases

MPConfigType

{ isDevelopmentMode?: boolean, dataPlan?: { planId?: string, planVersion?: number }, identifyRequest?: any, logLevel?: string, identityCallback?: (i: IdentityResult) => void, }

UserIdentities

{ customerid?: string; email?: string; other?: string; other2?: string; other3?: string; other4?: string; other5?: string; other6?: string; other7?: string; other8?: string; other9?: string; other10?: string; mobile_number?: string; phone_number_2?: string; phone_number_3?: string; facebook?: string; facebookcustomaudienceid?: string; google?: string; twitter?: string; microsoft?: string; yahoo?: string; }

MPID

string

Record

Construct a type with a set of properties K of type T

{ [P in K]: T; }

UserAttributesValue

string | number | boolean | null

AllUserAttributes

Record<string, UserAttributesValue | UserAttributesValue[]>

Product

{ name: string; sku: string; price: number; quantity?: number; variant?: string; category?: string; brand?: string; position?: number; coupon?: string; attributes?: Record<string, unknown>; }

Cart

{ /** * * @deprecated Cart persistence in mParticle has been deprecated. Please use mParticle.eCommerce.logProductAction(mParticle.ProductActionType.AddToCart, [products]) / add: (product: Product, logEventBoolean?: boolean) => void; /* * * @deprecated Cart persistence in mParticle has been deprecated. Please use mParticle.eCommerce.logProductAction(mParticle.ProductActionType.RemoveFromCart, [products]) / remove: (product: Product, logEventBoolean?: boolean) => void; /* * * @deprecated Cart persistence in mParticle has been deprecated. */ clear: () => void; }

GDPRConsentState

{ [key: string]: PrivacyConsentState; }

PrivacyConsentState

{ Consented: boolean; Timestamp: number; ConsentDocument: string; Location: string; HardwareId: string; }

CCPAConsentState

Omit<GDPRConsentState, 'purpose'>

Omit

Construct a type with the properties of T except for those in type K.

Pick<T, Exclude<keyof T, K>>

Pick

From T, pick a set of properties whose keys are in the union K

{ [P in K]: T[P]; }

Exclude

Exclude from T those types that are assignable to U

T extends U ? never : T

ConsentState

{ setGDPRConsentState: (gdprConsentState: GDPRConsentState) => ConsentState; setCCPAConsentState: (ccpaConsentState: CCPAConsentState) => ConsentState; addGDPRConsentState: ( purpose: string, gdprConsent: PrivacyConsentState, ) => ConsentState; getGDPRConsentState: () => GDPRConsentState; getCCPAConsentState: () => CCPAConsentState; removeGDPRConsentState: (purpose: string) => ConsentState; removeCCPAConsentState: () => ConsentState; }

User

{ getUserIdentities: () => UserIdentities; getMPID: () => MPID; setUserTag: (tag: string) => void; removeUserTag: (tag: string) => void; setUserAttribute: (key: string, value: string) => void; setUserAttributes: (attributeObject: Record<string, unknown>) => void; removeUserAttribute: (key: string) => void; setUserAttributeList: (key: string, value: UserAttributesValue[]) => void; removeAllUserAttributes: () => void; getUserAttributesLists: () => Record<string, UserAttributesValue[]>; getAllUserAttributes: () => AllUserAttributes; /** * * @deprecated Cart persistence in mParticle has been deprecated */ getCart: () => Cart; getConsentState: () => ConsentState; setConsentState: (ConsentState: ConsentState) => void; isLoggedIn: () => boolean; getLastSeenTime: () => number; getFirstSeenTime: () => number; }

IdentityResult

{ httpCode: any; getPreviousUser(): User; getUser(): User; body: IdentityResultBody; }