join us on Discord for support, updates, and all things Snap AR! See you there!
Quick Tip: If you are looking for launchParams, look here!
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!
Comments
-
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...
1 -
@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.
0 -
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
1 -
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.11 -
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.
1 -
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...
0 -
@Daniel eXplorins Just bumped up the ticket with our android eng now that he's back. Hang tight.
0 -
@stevenxu, thanks. Since we have a hardcoded workaround it's not super urgent, but defenitely something to solve ;-)
1 -
@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)
1 -
@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.
1 -
@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
1 -
@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 samekey
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.0 -
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
1 -
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" ?
0