Adobe Experience Platform Mobile SDKs – What changes need an app update?

I think I can safely say I speak for all of us when I say this: the first time I heard about Launch playing a role in the deployment of Experience Cloud applications on mobile, I immediately thought “tag management! On mobile! I wonder how far it goes!”

Ever since, I have wondered how much you can do with Launch in the context of mobile apps, and where the limits are that necessitate an update of the app.

Today I’m striving to find out!

Theory

In theory, this should be pretty simple: Any changes to the mobile Property in Launch that change the code to copy in the “Mobile install instructions” screen should clearly only make it into your app if you actually copy the code, build your app, release it as an update, and get your users to actually update. Any other changes to the mobile Property should be reflected in the settings, which the app will try to load when it launches.

In theory.

I’m guessing that this is true, in practice, too.

But it is somewhat hard for me to wrap my mind around, right now, so I think we should dive into the mobile Property, make changes, and see what happens.

As usual, this will be done with Android, but the same should apply to iOS apps.

To see what has changed in the settings, we need to see them. They live on the Launch infrastructure, and they can be queried via a simple HTTP GET request, if you know the URL. So where do you find that URL?

It’s simply the URL that the SDK uses in the MobileCore.configureWithAppID call, but with https://assets.adobedtm.com/ in front of it.

[screenshot]
The config URL in MainActivity.java & in the log
Ok. Down the rabbit hole we go.

Simple Test

Let’s start with the app as it is after the “Rerequisites” article from the mini-series. It’ll have two Extensions (Mobile Core and Profile), and we made changes in three files to make that happen (AndroidManifest.xml, build.gradle for the app, and MainActivity.java).

We made changes in the code, so this needs a release, obviously.

Querying the settings URL now returns a very simple configuration:

{
    "rules.url":"https://assets.adobedtm.com/3028746f70eb/f897e5e72b33/launch-5046ce31bc79-rules.zip",
    "experienceCloud.org":"BE5121AA565821017F000101@AdobeOrg",
    "lifecycle.sessionTimeout":300,
    "global.privacy":"optedin",
    "property.id":"PRcfe28858c9a441c6b3fb96f34cd4e9a2",
    "build.environment":"prod"
}

The “rules.url” attribute shows a URL, on which we can find more configuration, in this case about rules. The ...-rules.zip file contains another JSON snippet, which is even simpler:

{
    "version":1,
    "rules":[]
}

We haven’t created any Rules in the Launch UI, so the array of Rules is empty.

No surprises here. Moving on.

Test with Rule

Let’s make Data Elements and a Rule now!

With only the Mobile Core and Profile Extensions in our app, we don’t have a lot of things to do, but we can create Data Elements that reference internal values known in the SDK, such as device name, the Experience Cloud ID, or the number of the launch of the app.

We make a Rule using the new “Add Data” Action Type, which is probably worth an article, but for now we peruse the online documentation, which is a) pretty good, and b) has an example.

If we build a Library with our changes, and push it live, the settings URL will return almost the exact same thing as before. The only difference will be the URL to the ...-rules.zip file, which contains the real changes:

{
    "version":1,
    "rules":[
        {
            "condition":{
                "type":"group",
                "definition":{
                    "logic":"and",
                    "conditions":[
                        {
                            "type":"group",
                            "definition":{
                                "logic":"or",
                                "conditions":[
                                    {
                                        "type":"group",
                                        "definition":{
                                            "logic":"and",
                                            "conditions":[
                                                {
                                                    "type":"matcher",
                                                    "definition":{
                                                        "key":"~type",
                                                        "matcher":"eq",
                                                        "values":[
                                                            "com.adobe.eventType.generic.track"
                                                        ]
                                                    }
                                                },
                                                {
                                                    "type":"matcher",
                                                    "definition":{
                                                        "key":"~source",
                                                        "matcher":"eq",
                                                        "values":[
                                                            "com.adobe.eventSource.requestContent"
                                                        ]
                                                    }
                                                },
                                                {
                                                    "type":"matcher",
                                                    "definition":{
                                                        "key":"state",
                                                        "matcher":"ex",
                                                        "values":[

                                                        ]
                                                    }
                                                }
                                            ]
                                        }
                                    }
                                ]
                            }
                        }
                    ]
                }
            },
            "consequences":[
                {
                    "id":"RC12d6621ab2b24531a3a903bb7377ada9",
                    "type":"add",
                    "detail":{
                        "eventdata":{
                            "contextData":{
                                "launches":"{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.launches%}",
                                "deviceName":"{%~state.com.adobe.module.lifecycle/lifecyclecontextdata.devicename%}",
                                "experienceCloudId":"{%~state.com.adobe.module.identity/mid%}"
                            }
                        }
                    }
                }
            ]
        }
    ]
}

Nice!

I like that adding an Action Type to the Rule shows in the JSON as “consequences”. That’s funny.

You can also see how Data Elements are broken a bit further down.

“Device Name” becomes {%%Device Name%%} in the UI, and that turns into {%~state.com.adobe.module.lifecycle/lifecyclecontextdata.devicename%} in the JSON.

I’m curious now what other Action Types will look like, so…

More Extensions!

Let’s add the Analytics Extension.

Since we’re adding an Extension, we have to add code to build.gradle, and we have to therefore release. We also should add code to MainActivity.java, to add some analytics tracking to it.

Copy, code, build, test, release, update…

With that out of the way, let’s check the settings. Hitting the URL now returns this:

{
    "global.privacy":"optedin",
    "analytics.launchHitDelay":0,
    "analytics.backdatePreviousSessionInfo":false,
    "analytics.offlineEnabled":true,
    "__dev__analytics.rsids":"ags055w4dmobiledev",
    "build.environment":"prod",
    "rules.url":"https://assets.adobedtm.com/3028746f70eb/f897e5e72b33/launch-5046ce31bc79-rules.zip",
    "experienceCloud.org":"BE5121AA565821017F000101@AdobeOrg",
    "lifecycle.sessionTimeout":300,
    "analytics.server":"adobeags055.sc.omtrdc.net",
    "__stage__analytics.rsids":"ags055w4dmobiledev",
    "analytics.rsids":"ags055w4dmobileprod",
    "analytics.batchLimit":0,
    "property.id":"PRcfe28858c9a441c6b3fb96f34cd4e9a2",
    "analytics.aamForwardingEnabled":true
}

The URL for ...-rules.zip has not changed at this point, nor has the content, which makes sense.

It looks as if Extension settings are stored in the global context of the Mobile Property, and they are reflected in the JSON.

Sounds reasonable.

More Rules!

Let’s add another Rule.

It’ll be a silly Rule, because all we want to know is where the change will be visible.

So, let’s build one that uses “Mobile Core – Track Action” as the Event Type, and “Analytics – Track” as the Action Type. This will result in an additional server call, and you wouldn’t want to do this in any real life scenario.

 

[screenshot]
A simple, yet insane Rule
Low and behold, the JSON doesn’t change, but the ...-rules.zip file now contains a bigger block of JSON, and it does contain the new Rule.

The interesting part in the new rules file is this part:

"consequences": [
    {
        "id": "RC3f8ef02dfbb74cb5b7518073ded03cc2",
        "type": "an",
        "detail": {
            "state": "",
            "action": "Secondary",
            "contextdata": {
                "level": "2"
            }
        }
    }
]

If we add more Actions, then they are added to the array of consequences:

"consequences": [
    {
        "id": "RC46fe1196da6244c2a6424ba1d489d0f8",
        "type": "an",
        "detail": {
            "state": "",
            "action": "Secondary",
            "contextdata": {
                "level": "2"
            }
        }
    },
    {
        "id": "RCb67fa0ea3fd44aa1bdc550ad3e3ef24c",
        "type": "csp",
        "detail": {
            "key": "testKey",
            "value": "testValue",
            "operation": "write"
        }
    },
    {
        "id": "RCf1ccc8b739964ae48c95dfe23de09071",
        "type": "url",
        "detail": {
            "url": "https://www.jan-exner.de/"
        }
    },
    {
        "id": "RC83bb5957dbbb4952864088a93d49cb69",
        "type": "pb",
        "detail": {
            "timeout": 0,
            "templateurl": "https://www.jan-exner.de/orm/hook.php"
        }
    }
]

Again, that makes a lot of sense.

The part of this JSON that I find most interesting is the type that every consequence brings with it. I am guessing that this is how the code in the SDKs knows what to actually do at runtime.

The Rules Engine

The Mobile Core Extension comes with a thing called the “Rules Engine.”

It is that Rules Engine that adds flexibility to our app.

Whenever something happens in the app and the event handler inside the Mobile SDKs receives an event, the Rules Engine is queried. It goes through all conditions, and if necessary, all consequences.

The 4 different types in the JSON above (“an”, “csp”, “url, and “pb”) are part of the built-in types that come with the different Adobe Extensions.

You can see them all in the Consequence Types Table.

This is how the Rules Engine knows what to do, and it cements my understanding: you can only do things via Launch Rules for which actual code is already in the app. All that Launch does is to map Rules and existing code.

If you want more technical information about the Rules Engine, here you go: Rules Engine technical details

The flipside: as long as you do not add, enable, disable, or remove Extensions, changes that you make in Launch do not require an app update.

And that is all.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.