Skip to content

Commit

Permalink
Compose Firebase Dynamic Links (#1477)
Browse files Browse the repository at this point in the history
  • Loading branch information
argzdev committed May 23, 2023
1 parent b634e62 commit 8c3e5e5
Show file tree
Hide file tree
Showing 12 changed files with 623 additions and 127 deletions.
1 change: 1 addition & 0 deletions dynamiclinks/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ dependencies {
implementation "androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling-preview:$compose_version"
implementation 'androidx.activity:activity-compose:1.5.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1'

androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
Expand Down
14 changes: 12 additions & 2 deletions dynamiclinks/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

<activity android:name=".java.MainActivity"
android:exported="true">
<!-- [START link_intent_filter] -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
Expand All @@ -28,7 +27,6 @@
android:host="example.com"
android:scheme="https"/>
</intent-filter>
<!-- [END link_intent_filter] -->
</activity>

<activity android:name=".kotlin.MainActivity"
Expand All @@ -42,6 +40,18 @@
android:scheme="https"/>
</intent-filter>
</activity>

<activity android:name=".kotlin.MainComposeActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data
android:host="kotlin.example.com"
android:scheme="https"/>
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ class EntryChoiceActivity : BaseEntryChoiceActivity() {
Choice(
"Kotlin",
"Run the Firebase Dynamic Links quickstart written in Kotlin.",
Intent(this, com.google.firebase.quickstart.deeplinks.kotlin.MainActivity::class.java))
Intent(this, com.google.firebase.quickstart.deeplinks.kotlin.MainActivity::class.java)),
Choice(
"Compose",
"Run the Firebase Dynamic Links quickstart written in Compose.",
Intent(this, com.google.firebase.quickstart.deeplinks.kotlin.MainComposeActivity::class.java))
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,8 @@ public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private static final String DEEP_LINK_URL = "https://example.com/deeplinks";

// [START on_create]
@Override
protected void onCreate(Bundle savedInstanceState) {
// [START_EXCLUDE]
super.onCreate(savedInstanceState);
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
Expand Down Expand Up @@ -89,9 +87,7 @@ public void onClick(View v) {
buildShortLinkFromParams(deepLink, 0);
}
});
// [END_EXCLUDE]

// [START get_deep_link]
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, new OnSuccessListener<PendingDynamicLinkData>() {
Expand All @@ -109,7 +105,6 @@ public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
// account.
// ...

// [START_EXCLUDE]
// Display deep link in the UI
if (deepLink != null) {
Snackbar.make(findViewById(android.R.id.content),
Expand All @@ -119,7 +114,6 @@ public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
} else {
Log.d(TAG, "getDynamicLink: no link found");
}
// [END_EXCLUDE]
}
})
.addOnFailureListener(this, new OnFailureListener() {
Expand All @@ -128,9 +122,7 @@ public void onFailure(@NonNull Exception e) {
Log.w(TAG, "getDynamicLink:onFailure", e);
}
});
// [END get_deep_link]
}
// [END on_create]

/**
* Build a Firebase Dynamic Link.
Expand All @@ -152,7 +144,6 @@ public Uri buildDeepLink(@NonNull Uri deepLink, int minVersion) {
// * URI prefix (required)
// * Android Parameters (required)
// * Deep link
// [START build_dynamic_link]
DynamicLink.Builder builder = FirebaseDynamicLinks.getInstance()
.createDynamicLink()
.setDomainUriPrefix(uriPrefix)
Expand All @@ -163,7 +154,6 @@ public Uri buildDeepLink(@NonNull Uri deepLink, int minVersion) {

// Build the dynamic link
DynamicLink link = builder.buildDynamicLink();
// [END build_dynamic_link]

// Return the dynamic link as a URI
return link.getUri();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package com.google.firebase.quickstart.deeplinks.kotlin

import android.content.Intent
import android.net.Uri
import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import com.google.firebase.dynamiclinks.FirebaseDynamicLinks
import com.google.firebase.dynamiclinks.PendingDynamicLinkData
import com.google.firebase.dynamiclinks.ktx.androidParameters
import com.google.firebase.dynamiclinks.ktx.dynamicLink
import com.google.firebase.dynamiclinks.ktx.dynamicLinks
import com.google.firebase.dynamiclinks.ktx.shortLinkAsync
import com.google.firebase.ktx.Firebase
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await

class DynamicLinksViewModel(
private val dynamicLinks: FirebaseDynamicLinks
): ViewModel() {

private val _deepLink = MutableStateFlow("")
val deepLink: StateFlow<String> = _deepLink

private val _shortLink = MutableStateFlow("")
val shortLink: StateFlow<String> = _shortLink

private val _validUriPrefix = MutableStateFlow(true)
val validUriPrefix: StateFlow<Boolean> = _validUriPrefix

fun getDynamicLink(intent: Intent) {
viewModelScope.launch {
try {
val pendingDynamicLinkData: PendingDynamicLinkData = dynamicLinks
.getDynamicLink(intent)
.await()

val deepLink: Uri? = pendingDynamicLinkData.link

// Handle the deep link. For example, open the linked
// content, or apply promotional credit to the user's
// account.
// ...

// Display deep link in the UI
if (deepLink != null) {
_deepLink.value = deepLink.toString()
} else {
Log.d(TAG, "getDynamicLink: no link found")
}
} catch (e: Exception) {
Log.w(TAG, "getDynamicLink:onFailure", e)
}
}
}


/**
* Build a Firebase Dynamic Link.
* https://firebase.google.com/docs/dynamic-links/android/create#create-a-dynamic-link-from-parameters
*
* @param deepLink the deep link your app will open. This link must be a valid URL and use the
* HTTP or HTTPS scheme.
* @param minVersion the `versionCode` of the minimum version of your app that can open
* the deep link. If the installed app is an older version, the user is taken
* to the Play store to upgrade the app. Pass 0 if you do not
* require a minimum version.
* @return a [Uri] representing a properly formed deep link.
*/
// @VisibleForTesting
fun buildDeepLink(uriPrefix: String, deepLink: Uri, minVersion: Int): Uri {
// Set dynamic link parameters:
// * URI prefix (required)
// * Android Parameters (required)
// * Deep link
// Build the dynamic link
val link = Firebase.dynamicLinks.dynamicLink {
domainUriPrefix = uriPrefix
androidParameters {
minimumVersion = minVersion
}
link = deepLink
}

// Return the dynamic link as a URI
return link.uri
}

// @VisibleForTesting
fun buildShortLinkFromParams(uriPrefix: String, deepLink: Uri, minVersion: Int) {
// Set dynamic link parameters:
// * URI prefix (required)
// * Android Parameters (required)
// * Deep link

try {
viewModelScope.launch {
val shortDynamicLinks = Firebase.dynamicLinks.shortLinkAsync {
link = deepLink
domainUriPrefix = uriPrefix
androidParameters {
minimumVersion = minVersion
}
}.await()

val shortLinks = shortDynamicLinks.shortLink
// val flowChartLink = shortDynamicLinks.previewLink

_shortLink.value = shortLinks.toString()
}
} catch (e: Exception) {
Log.e(TAG, e.toString())
}
}

fun validateAppCode(uriPrefix: String) {
if (uriPrefix.contains("YOUR_APP")) {
_validUriPrefix.value = false
}
}

companion object {
const val TAG = "DynamicLinksViewModel"

// Used to inject this ViewModel's dependencies
// See also: https://developer.android.com/topic/libraries/architecture/viewmodel/viewmodel-factories
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
// Get Remote Config instance.
val dynamicLinks = Firebase.dynamicLinks
return DynamicLinksViewModel(dynamicLinks) as T
}
}
}
}
Loading

0 comments on commit 8c3e5e5

Please sign in to comment.