Heads up! We're sunsetting this forum to streamline our community space.

join us on Discord for support, updates, and all things Snap AR! See you there!
Sign up for our live Camera Kit office hour on July 17 @ 9:30am (PT) / 4:30pm (GMT)

Quick Tip: If you are looking for launchParams, look here!

aidan
aidan Posts: 32 🔥
edited March 2023 in General #1

Hi y'all,

A big thing I was looking for is launchParams and yes it's supported by CameraKit and yes it's quite easy to implement. If you aren't familiar with launchParams it lets you pass data into your Lens meaning you can change a model's color or do some action depending on the entry point. Read more about it here: https://docs.snap.com/lens-studio/references/guides/distributing/snap-kit

Here's the working code to bring launchParams into CameraKit

CameraController.swift already has a function called:

public func applyLens(_ lens: Lens, completion: ((Bool) -> Void)? = nil)

However it doesn't seem possible to pass launchParams to it out of the box (as it opts to use vendorData set up in the CameraKit portal). Instead, we can add an extension for CameraController and create our own applyLens:

extension CameraController {
    public func applyLensWithLaunchParams(_ lens: Lens,_ launchParams: [String:String]? = nil) {

        let launchDataBuilder = LensLaunchDataBuilder()
        for (key, val) in launchParams! {
            launchDataBuilder.add(string: val, key: key)
        }

        self.cameraKit.lenses.processor?.apply(lens: lens, launchData: launchDataBuilder.launchData, completion: nil)
    }
}

Just copy this into a Swift script in your project. Then you can call it anywhere you would use applyLens. Hope this helps someone out there!

Tagged:

Comments

  • stevenxu
    stevenxu Posts: 612 👻

    OMG @aidan thank you for putting this together for the community!!!! Coming in clutch with this!!!

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    Good job @aidan

    That iOS one worked very straight forward on our side as well.

    However, I am currently fighting with the Android version of it.

    After using the LaunchData Builder

    val dataBuilder = LensesComponent.Lens.LaunchData.newBuilder() dataBuilder.putStrings(key, itemValue)

    I get an object like this:

    launchData =
    DefaultLaunchData(launchDataMap={titles=[Ljava.lang.String;@f744385, hallo=Klaus, descriptions=[Ljava.lang.String;@dbe90e8, ctaTexts=[Ljava.lang.String;@6bc5e3d, interactionTitles=[Ljava.lang.String;@4696f83, interactionTexts=[Ljava.lang.String;@715a139, interactionButtonConfirmTexts=[Ljava.lang.String;@6c980df, interactionButtonBackTexts=[Ljava.lang.String;@f2617f5, interactionPlaceholderTexts=[Ljava.lang.String;@7ef4bfb, successReplyTexts=[Ljava.lang.String;@38d3e71, interactionSolutionTexts=[Ljava.lang.String;@8903456})

    Later I try to apply this to an lense

    Session?.lenses?.processor?.apply(lens, launchData)

    However, nothing get applied to any lens.

    On iOS we are using the very same input params and everything works just perfectly.

    Any ideas?

    Thanks a lot in advance, this has really taken a lot of time already...

  • stevenxu
    stevenxu Posts: 612 👻

    @Daniel eXplorins Great to see @aidan 's post was helpful for ya on the iOS side! Regarding the Android side.. I created an eng ticket to investigate. This one may take a while as the assigned eng is out of office till end of this week. Appreciate your patience in advance.

    In the meantime, could you share me the following info (if available):

    • Steps to reproduce
    • Lens Name
    • Lens ID
    • Platform : iOS / Android
    • Devices Affected : iPhone / Android Device Model & Manufacturer
    • CameraKit SDK version

    Will add this info to the ticket so they can fully diagnose.

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    Thx @stevenxu . Actually we've done iOS integrating already before seeing @aidan 's post , however still good job ;-)

    Regarding Android integration:

    The correct way of calling apply is of course like this (haven't posted the callback before.):
    Session?.lenses?.processor?.apply(lens, launchData, {callback})

    However, this unfortunaltely doesn't do the trick.

    I have tried several data formats since
    putStrings(key: String, vararg value: String)
    is taking multiple params.

    In sample code you are using only
    putString(key: String, value: String)

    Since our lenses take Strings[] as LaunchParams I haven't checked with single String input yet, but maybe the issue is related to that....

    Looking forward to your feedback

    Thanks

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    regarding Bug Report:
    Steps to reproduce --> see my first comment
    Lens Name --> any of our lenses, which work perfectly on iOS
    Lens ID --> any
    Platform : iOS / Android --> Android
    Devices Affected : iPhone / Android Device Model & Manufacturer --> Android Studio
    CameraKit SDK version --> 1.21.1

  • Hey @Daniel eXplorins

    Just tested this out by adapting MainActivity.kt from the VendorData example and was able to get it to send into the Lens.

                        val launchData = LensesComponent.Lens.LaunchData {
                                putString("Key1", "Val1")
                                putNumber("Key2", 100)
                                putStrings("Key3", "a","b","c","d")
                                putNumbers("Key4", 0,1,2,3,4,5,6,7)
                        }
                        session.lenses.processor.apply(lens, launchData) { success ->
                            Log.d(TAG, "Apply lens [$lens] with launch data [$launchData] success: $success")
                        }
    

    for testing I had just done this in the reApplyLensWithVendorData example, for some reason this did cause a flicker of reapplying the Lens repeatedly so I added a flag to only send it once.

    Hopefully this can provide a lead towards your solution until an Android expert is able to respond.

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    So far no luck on this. We hardcoded in for now, however I wanna get the trick.
    Is it about reapplying the lens for a 2nd time?

    Just following the super straight forward iOS logic just doesn´t work for me here...

  • stevenxu
    stevenxu Posts: 612 👻
    edited April 2023 #9

    @Daniel eXplorins Just bumped up the ticket with our android eng now that he's back. Hang tight.

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    @stevenxu, thanks. Since we have a hardcoded workaround it's not super urgent, but defenitely something to solve ;-)

  • Ankit Baphna
    Ankit Baphna Posts: 12 👻

    @Daniel eXplorins have you tried the single string yet? Any issues with that or only issue is with putStrings?

    Reg. reapplying, you don't have to apply the Lens twice. Doing it once with launchData should work fine. Also, make sure to apply the Lens from UI thread. Here is the code that worked for me fine from UI thread.

    val launchData =  LensesComponent.Lens.LaunchData.newBuilder()
    launchData.putString("text", "test data")
    val vendorData =  launchData.build()
    cameraKitSession.lenses.processor.apply(lens, vendorData) 
    
  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    @Ankit Baphna thanks for your reply.

    Nope, still no luck.

    cameraKitSession!!.lenses?.repository?.observe(
                        queryCriteria
                    ) { result ->
                        result.whenHasSome { lenses ->
                            this@SnapActivity.runOnUiThread {
                                val launchData = LensesComponent.Lens.LaunchData.newBuilder()
                                launchData.putString("title", "test data")
                                launchData.putStrings("titles", "result", "hallo", "test")
                                val vendorData = launchData.build()
                                cameraKitSession?.lenses?.processor?.apply(lenses.first(), vendorData)
                            };
                        }
    

    The lens is getting applied, but without launch data...
    Even literally taking your example. On the other hand on iOS the same lens is taking launchParams without any problem.

    Strange.

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥
    edited April 2023 #13

    @Ankit Baphna it's me again.

    So, I ran my lens with your sample app, and even there it's not applying any launch params. So it's not a coding issue. However, the same lens' launch params work just fine on ios. The lens you were testing with is the "Big Mouth big eyes"? I would like to test it with a lens where launch params work for sure...

    Thank you

  • Ankit Baphna
    Ankit Baphna Posts: 12 👻

    @Daniel eXplorins thanks for trying. The key that you pass through putString(s), and putNumber(s) must match with the key that you use in the Lens code. I was trying on a Lens that I built and not any pre-built Lenses that we provide, most certainly not the Big Mouth Lens. Can you please make sure you are using the same key across iOS, Android and the Lens? If you post your Lens logic to read the params then that would give us more insights as well.

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥
    edited April 2023 #15

    Hi @Ankit Baphna , thanks for getting back.
    Yes, keys are the same in iOS and Android, because they are coming from our DB at our backend.

    Later in the lens we are doing this:

    Script on Create:

    function getLaunchParams(){
        if(Object.keys(global.launchParams).length === 0) {
            var launchParams = new mockLaunchParams();
            return populateMockParams(launchParams)
        }
        return global.launchParams   
    }
    
    function mockLaunchParams () {
        this.isMocked = true;
        const storedTypes = ["Float", "String"];
        this.store = {};
        this.has = function (key) {
            return this.store[key] !== undefined;
        }
    
        for (var k in storedTypes) {
            var typeName = storedTypes[k];
    
            this["put" + typeName] = function (key, value) {
                this.store[key] = value;
            };
    
            this["put" + typeName + "Array"] = function (key, value) {
                this.store[key] = value;
            };
    
            this["get" + typeName] = function (key) {
                return this.store[key];
            };
    
            this["get" + typeName + "Array"] = function (key) {
                return this.store[key];
            };
        }
    }
    
    // get set 
    function populateMockParams(params) {
        params.putStringArray("titles", ['La Cronolupa'])
    params.putStringArray("ctaTexts", ['Començar'])
        params.putStringArray("interactionPlaceholderTexts",['Escriu la resposta'])
        ...
    
        return params
    }
    global.launchParamsStore = getLaunchParams()
    

    Script from camera to apply params:

    var launchParams = global.launchParamsStore
    
    var titles
    var ctaTexts
    var interactionPlaceholders
    
    
    var order = script.paramsIndex
    
    function getData(){
    
        if(launchParams) {
    
            titles = launchParams.getStringArray("titles")
            if(titles && titles[order] && script.titleText) script.titleText.text = titles[order]
    
            ctaTexts = launchParams.getStringArray("ctaTexts")
            if(ctaTexts && ctaTexts[order] && script.ctaText) script.ctaText.text = ctaTexts[order]
    
            interactionPlaceholders = launchParams.getStringArray("interactionPlaceholderTexts")
            if(interactionPlaceholders && interactionPlaceholders[order] && script.interactionPlaceholder) script.interactionPlaceholder.text = interactionPlaceholders[order]
    
            return true
    
        } return false
    }
    
    if(!getData()) print("Failed to get data")
    

    This logic is very much inspired by your examples.

    Strange thing is that it works on iOS but not on Android.

    Thanks.

    EDIT:

    I just made another test and it is also applying well my mocked fallback params.

    So basically here it does NOT find any keys on Android, while iOS works as expected:

    function getLaunchParams(){
        if(Object.keys(global.launchParams).length === 0) {
            var launchParams = new mockLaunchParams();
            return populateMockParams(launchParams)
        }
        return global.launchParams   
    }
    

    Thanks

  • Daniel eXplorins
    Daniel eXplorins Posts: 11 🔥

    Hi @Ankit Baphna , sorry for being stuck on this topic. From what you see (my post above), does this make any sense to you that on Android the lens is just not recognizing "global.launchParams" ?

Categories