Android Question [solved] Firebase AppInvites

DonManfred

Expert
Licensed User
Longtime User
I am creating this thread because i am writing a wrap for the Firebase AppInvites and i need some help.

Hopefully one of you know the answer.

In the moment i stuck finding the right import to use in #additionaljar for the Firebase DynamicLinks

Logger verbunden mit: 9885e6514556383552
--------- beginning of crash
--------- beginning of main
--------- beginning of system
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
#-Activity_Resume
x53, iStart.Action=android.intent.action.MAIN
x54, iStart.ExtrasToString=no extras
#-Button1_Click
** Activity (main) Pause, UserClosed = false **
** Activity (prepmessage) Create, isFirst = true **
prepmessage_activity_create (java line: 343)
java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/firebase/dynamiclinks/FirebaseDynamicLinks;
at de.donmanfred.FirebaseDynamicLinkswrapper.Initialize(FirebaseDynamicLinkswrapper.java:44)
at b4a.example.fibainv.prepmessage._activity_create(prepmessage.java:343)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:186)
at b4a.example.fibainv.prepmessage.afterFirstLayout(prepmessage.java:102)
at b4a.example.fibainv.prepmessage.access$000(prepmessage.java:17)
at b4a.example.fibainv.prepmessage$WaitForLayout.run(prepmessage.java:80)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6692)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1468)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1358)
Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.firebase.dynamiclinks.FirebaseDynamicLinks" on path: DexPathList[[zip file "/data/app/b4a.example.fibainv-1/base.apk"],nativeLibraryDirectories=[/data/app/b4a.example.fibainv-1/lib/arm64, /system/lib64, /vendor/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:56)
at java.lang.ClassLoader.loadClass(ClassLoader.java:380)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 14 more

The 1st version of the lib is attached including a example project.

If anyone have a hint what i should use in the #additionalar: please share
 
Last edited:

Erel

B4X founder
Staff member
Licensed User
Longtime User
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
Attached Testproject 06 compiles now without error.

The result with some testsettings:
#- x67, strDynamicLink=com.google.firebase.dynamiclinks.DynamicLink@55a21d2

The expectation was a URL...

B4X:
Sub btnSend_Click
    Log("#-PrepMessage.btnSend_Click")
   
   
    '├
    '├ TODO: Create and send "Dynamic link" via intent
    '├

    ' ─────────────────
    ' This needs to be translated to a B4A Intent "AppInviteInvitation"   
    ' ─────────────────
    ' Info -->    https://github.com/firebase/quickstart-android/blob/master/invites/app/src/main/java/com/google/firebase/quickstart/invites/MainActivity.java#L119-L127
    '
    '                    // [START on_invite_clicked]
    '                    Private void onInviteClicked() {
    '                        Intent intent = new AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
    '                                .setMessage(getString(R.string.invitation_message))
    '                                .setDeepLink(Uri.parse(getString(R.string.invitation_deep_link)))
    '                                .setCustomImage(Uri.parse(getString(R.string.invitation_custom_image)))
    '                                .setCallToActionText(getString(R.string.invitation_cta))
    '                                .build();
    '                        startActivityForResult(intent, REQUEST_INVITE);
    '                    }
    '                    // [END on_invite_clicked]
    ' ─────────────────   
   

    ' Some basic testings:
    Dim fbdl As FirebaseDynamicLinks
    fbdl.Initialize("fbdl")
    fbdl.DynamicLinkDomain = "basic4android.de"
    fbdl.setAndroidParameters("http://fallback", 1)
    fbdl.setGoogleAnalyticsParameters("campaign", "content", "medium", "source", "term")
    fbdl.setIosParameters("unknownparameter", "appstoreID", "customscheme", "fallbackurl", "ipadBundleId", "iPadFallbackurl", 1)
    fbdl.setItunesConnectAnalyticsParameters("AffiliateId", "CampaignToken", "ProviderToken")
    fbdl.setSocialMetaTagParameters("description", "imageUrl", "title")
   
    Dim strDynamicLink As String = fbdl.BuildDynamicLink
   
    Log($"#-  x67, strDynamicLink=${strDynamicLink}"$)   
    ' Result from log: #-  x67, strDynamicLink=com.google.firebase.dynamiclinks.DynamicLink@55a21d2




   
    ToastMessageShow("Message sent", True)
 

Attachments

  • fibainvites_06.zip
    18.4 KB · Views: 402
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
btnSend_Click
...
fbdl.buildShortDynamicLink
...
See logpoint x72:

B4X:
    ' TODO [1]: Create "Dynamic link"
    ' some testsettings
    Dim fbdl As FirebaseDynamicLinks
    fbdl.Initialize("fbdl")
    fbdl.DynamicLinkDomain = "basic4android.de"
    fbdl.setAndroidParameters("http://fallback", 1)
    fbdl.setGoogleAnalyticsParameters("campaign", "content", "medium", "source", "term")
    fbdl.setIosParameters("unknownparameter", "appstoreID", "customscheme", "fallbackurl", "ipadBundleId", "iPadFallbackurl", 1)
    fbdl.setItunesConnectAnalyticsParameters("AffiliateId", "CampaignToken", "ProviderToken")
    fbdl.setSocialMetaTagParameters("description", "imageUrl", "title")
   
   
    Dim strDynamicLink As String = fbdl.BuildDynamicLink
    Log($"#-  x67, strDynamicLink=${strDynamicLink}"$)
    '   Result:
    '          from log: #-  x67, strDynamicLink=com.google.firebase.dynamiclinks.DynamicLink@55a21d2

    Log($"#-  x72, trying fbdl.buildShortDynamicLink"$)
    fbdl.buildShortDynamicLink
    '   Result:
    '          from log: #-  x72, trying fbdl.buildShortDynamicLink
    '            com.google.android.gms.tasks.RuntimeExecutionException: com.google.android.gms.common.api.ApiException: Bad Request
    '                at com.google.android.gms.tasks.zzn.getResult(Unknown Source:14)
    '                at de.donmanfred.FirebaseDynamicLinkswrapper$1.onComplete(FirebaseDynamicLinkswrapper.java:55)
    '                at com.google.android.gms.tasks.zzf.run(Unknown Source:23)
    '                at android.os.Handler.handleCallback(Handler.java:789)
    '                at android.os.Handler.dispatchMessage(Handler.java:98)
    '                at android.os.Looper.loop(Looper.java:164)
    '                at android.app.ActivityThread.main(ActivityThread.java:6541)
    '                at java.lang.reflect.Method.invoke(Native Method)
    '                at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
    '                at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
    '            Caused by: com.google.android.gms.common.api.ApiException: Bad Request
    '                at com.google.android.gms.internal.zzber.zza(Unknown Source:12)
    '                at com.google.android.gms.internal.zp.zza(Unknown Source:2)
    '                at com.google.android.gms.internal.zu.onTransact(Unknown Source:51)
    '                at android.os.Binder.execTransact(Binder.java:674)
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Bad Request
bad request is a indication that there are wrong parameters...
it looks like some kind of a pointer
it is a DynamicLink Object... I need to revisit the method to return a valid Object (write a wrapper for this object).
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
B4X:
    Dim dynlink As DynamicLink = fbdl.BuildDynamicLink
    Log($"#-  x67, strDynamicLink=${dynlink.Parameters}"$)
    For Each key As String In dynlink.Parameters.Keys
        Log($"#-  x67a, ${key}=${dynlink.Parameters.Get(key)}"$)      
    Next


Parameters is a Map
** Activity (prepmessage) Resume **
** Activity (prepmessage) Pause, UserClosed = true **
** Activity (main) Resume **
x52, Main.Activity_Resume
x53, iStart.Action=android.intent.action.MAIN
x54, iStart.ExtrasToString=no extras
** Activity (main) Pause, UserClosed = true **
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
x52, Main.Activity_Resume
x53, iStart.Action=android.intent.action.MAIN
x54, iStart.ExtrasToString=no extras
#-Main.Button1_Click
** Activity (main) Pause, UserClosed = false **
** Activity (prepmessage) Create, isFirst = true **
** Activity (prepmessage) Resume **
#-PrepMessage.btnSend_Click
#- x67, strDynamicLink={DeepLink=https://basic4android.de?utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http://fallback&amv=1&apn=b4a.example.fibainv&ibi=unknownparameter&ifl=fallbackurl&imv=1&isi=appstoreID&ius=customscheme&ipbi=ipadBundleId&ipfl=iPadFallbackurl&utm_term=term&utm_medium=medium&utm_source=source, Authority=basic4android.de, EncodedAuthority=basic4android.de, EncodedFragment=null, EncodedPath=, EncodedQuery=utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http%3A%2F%2Ffallback&amv=1&apn=b4a.example.fibainv&ibi=unknownparameter&ifl=fallbackurl&imv=1&isi=appstoreID&ius=customscheme&ipbi=ipadBundleId&ipfl=iPadFallbackurl&utm_term=term&utm_medium=medium&utm_source=source, EncodedSchemeSpecificPart=//basic4android.de?utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http%3A%2F%2Ffallback&amv=1&apn=b4a.example.fibainv&ibi=unknownparameter&ifl=fallbackurl&imv=1&isi=appstoreID&ius=customscheme&ipbi=ipadBundleId&ipfl=iPadFallbackurl&utm_term=term&utm_medium=medium&utm_source=source, EncodedUserInfo=null, Fragment=null, Host=basic4android.de, LastPathSegment=null, Path=, Query=utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http://fallback&amv=1&apn=b4a.examp...erm=term&utm_medium=medium&utm_source=source}
#- x67a, DeepLink=https://basic4android.de?utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http://fallback&amv=1&apn=b4a.example.fibainv&ibi=unknownparameter&ifl=fallbackurl&imv=1&isi=appstoreID&ius=customscheme&ipbi=ipadBundleId&ipfl=iPadFallbackurl&utm_term=term&utm_medium=medium&utm_source=source
#- x67a, Authority=basic4android.de
#- x67a, EncodedAuthority=basic4android.de
#- x67a, EncodedFragment=null
#- x67a, EncodedPath=
#- x67a, EncodedQuery=utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http%3A%2F%2Ffallback&amv=1&apn=b4a.example.fibainv&ibi=unknownparameter&ifl=fallbackurl&imv=1&isi=appstoreID&ius=customscheme&ipbi=ipadBundleId&ipfl=iPadFallbackurl&utm_term=term&utm_medium=medium&utm_source=source
#- x67a, EncodedSchemeSpecificPart=//basic4android.de?utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http%3A%2F%2Ffallback&amv=1&apn=b4a.example.fibainv&ibi=unknownparameter&ifl=fallbackurl&imv=1&isi=appstoreID&ius=customscheme&ipbi=ipadBundleId&ipfl=iPadFallbackurl&utm_term=term&utm_medium=medium&utm_source=source
#- x67a, EncodedUserInfo=null
#- x67a, Fragment=null
#- x67a, Host=basic4android.de
#- x67a, LastPathSegment=null
#- x67a, Path=
#- x67a, Query=utm_content=content&utm_campaign=campaign&at=AffiliateId&ct=CampaignToken&pt=ProviderToken&sd=description&si=imageUrl&st=title&afl=http://fallback&amv=1&apn=b4a.examp...term=term&utm_medium=medium&utm_source=source
** Activity (prepmessage) Pause, UserClosed = false **
** Activity (prepmessage) Resume **

PD: V0.11 - not yet published (still working on it)
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
A bit further.... We need to find out the right parameters we want to set

Attention: Line 63
B4X:
fbdl.DynamicLinkDomain = "xxxx" '  prefix from "xxxx.app.goo.gl"

Dynamic link creation
B4X:
    Dim dynlink As DynamicLink = fbdl.BuildDynamicLink
    Log($"#-  x67, strDynamicLink=${dynlink.Parameters}"$)
    For Each key As String In dynlink.Parameters.Keys
        Log($"#-  x67a, ${key}=${dynlink.Parameters.Get(key)}"$) 
    Next

To create a short dynamic link we need to go another way.

See this new sub signature (and code)

B4X:
Sub fbdl_onComplete(shortinktask As Object)
    Log("#-fbdl_onComplete")
    Dim task As JavaObject = shortinktask
    Do While task.RunMethod("isComplete", Null) = False
        Log($"#-  x67b, sleep(100)"$)
        Sleep(100)
    Loop
    Log($"#-  x67c, task beendet"$)
    'Log("#-  x44, previewLink=" & previewLink)
    'Log("#-  x45, shortLink=" & shortLink)

End Sub

At the end the task is finished but raises the failure event... Probably of the wrong parameters. We need to investigate
 
Last edited:
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
V2.20 fixes it
Great. I was trying to find the imports for hours. Then i decided to post here to maybe get a hint.
Did´nt expect the sdkmanager was the problem :D

But it is working now. Ok, with issues but we came further ;-)
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
As far as i did understand the documentation (i may be wrong).
To use the deeplink we need to have an App with a packagename which is also a valid https website. Packagename in reverseorder.

for ex. i own the domain basic4android.de
i have a subdomain fbdl in this domain. which results in fbdl.basic4android.de

If i understand it right then i need to have a packagename de.basic4android.fbdl inside my App to allow it google to forward a user to my app.

Any comments on this?
 
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
...which is also a valid https website...?
No.

What might be helping is the thought that we could create a Dynamic Link manually

https://app_code.app.goo.gl/
?link=your_deep_link
&apn=package_name
[&amv=minimum_version]
[&al=android_link]
[&afl=fallback_link]​

According to this we need minimum:
a) the app_code
a) the app's package_name that corresponds to the Firebase project's Settings for this app
b) your_deep_link which holds a well formed URL with 2 parts
b1) the host info you have set up in the Manifest as an intent filter (...<data android:host="yourapp.com"...)
b2) the payload that should be handled by the Activity to which the intentfilter points to​
The other parameters control the behavior if the receiving device doesn't have the app (package_name) installed and optional Analytics settings.​


The link in Firebase's debug mode shows a graphical representation:
https://z3dz3.app.goo.gl/?link=http...m/showdat/data123&apn=b4a.example.fibainv&d=1
 
Upvote 0

fredo

Well-Known Member
Licensed User
Longtime User
How can it help with using the Library?

#16 was only intendet to give additional background information on the DynamicLink structure.


The library would be an "out-of-the-box" solution to build an "AppInviteInvitation"-Intent.

This is how it is used in the Firebase Quickstart example for Invites:
B4X:
    '                    // [START on_invite_clicked]
    '                    Private void onInviteClicked() {
    '                        Intent intent = new AppInviteInvitation.IntentBuilder(getString(R.string.invitation_title))
    '                                .setMessage(getString(R.string.invitation_message))
    '                                .setDeepLink(Uri.parse(getString(R.string.invitation_deep_link)))
    '                                .setCustomImage(Uri.parse(getString(R.string.invitation_custom_image)))
    '                                .setCallToActionText(getString(R.string.invitation_cta))
    '                                .build();
    '                        startActivityForResult(intent, REQUEST_INVITE);
    '                    }
    '                    // [END on_invite_clicked]


The user experience would be an Activity that offers this:

16-09-_2017_15-17-21.png
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
The library would be an "out-of-the-box" solution to build an "AppInviteInvitation"-Intent

The intentbuilder i have implemented. See new lib attached.
Did not tried it. dont know what happen if you call build :)

B4X:
package de.donmanfred;

import com.google.android.gms.appinvite.AppInviteInvitation;
import com.google.android.gms.appinvite.AppInviteInvitation.IntentBuilder;

import android.content.Intent;
import android.net.Uri;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.BA.Events;
import anywheresoftware.b4a.BA.ShortName;
import anywheresoftware.b4a.IOnActivityResult;
import anywheresoftware.b4a.objects.collections.List;

@ShortName("AppInviteInvitationBuilder")
//@Permissions(values={"android.permission.INTERNET", "android.permission.ACCESS_NETWORK_STATE"})
@Events(values={"onInvite(invites As List)"})
//@DependsOn(values={"com.google.firebase:firebase-appindexing"})
public class AppInviteInvitationBuilderwrapper  {
    private BA ba;
    private String eventName;
    private IntentBuilder builder;
    private IOnActivityResult ion;
    /*
     * Initialize the HTML-TextView
     */   
    public void Initialize(final BA ba, String EventName, String title) {
        this.eventName = EventName.toLowerCase(BA.cul);
        this.ba = ba;
        builder = new AppInviteInvitation.IntentBuilder(title);

    ion = new IOnActivityResult() {
        
            @Override
            public void ResultArrived(int resultCode, Intent data) {
                ba.Log("ResultArrived("+resultCode+")");
                ba.Log("ResultArrived()");
                List l = new List();
                l.Initialize();
                String[] ids = AppInviteInvitation.getInvitationIds(resultCode, data);
                for (String id : ids) {
                    l.Add(id);
                }
                ba.raiseEventFromDifferentThread(this, null, 0, eventName + "_oninvite", true, new Object[] {l});            
            
            }
        };    
    }
    public void build(){
        ba.startActivityForResult(ion, builder.build());
    }
    public void setMessage(CharSequence invitation_message){
        builder.setMessage(invitation_message);
    }
    public void setDeepLink(String invitation_deep_link){
        builder.setDeepLink(Uri.parse(invitation_deep_link));
    }
    public void setCustomImage(String invitation_custom_image){
        builder.setCustomImage(Uri.parse(invitation_custom_image));
    }
    public void setCallToActionText(CharSequence invitation_cta){
        builder.setCallToActionText(invitation_cta);
    }



}

The Object AppInviteInvitationBuilder is new in this Version...
Attention: New Event onInvite(invites As List)
 
Last edited:
Upvote 0
Top