i'm working on email verification. Email reaches the mailbox and when the user clicks on the link it moves him to the application. When I try to get data from link in getDynamicLinks method, pendingDynamicLinkData is null. But i can get the link from intent.
Link looks like: (https://travellersystems.page.link?link=https://traveller-249409.firebaseapp.com/__/auth/action?apiKey%3DAIzaSyCrwQqjOn5v4BDdkKCZHMmmav1YEzvaq5s%26mode%3DverifyEmail%26oobCode%3D0fQfmM0UAHrdNQbUyntffzFH39GtEODVCiVfnrcD0VUAAAFtIQ0HyQ%26continueUrl%3Dhttps://travellersystems.page.link/verify?email%253Ddaniellegawiec20#gmail.com%26lang%3Dpl&apn=com.client.traveller&amv)
Here I want to get email from the continueURL.
Here i create dynamic link and i'm sending verification email to the user
val url = "https://travellersystems.page.link/verify?email=${FirebaseAuth.getInstance().currentUser?.email}"
val dynamicLink = FirebaseDynamicLinks.getInstance().createDynamicLink()
.setLink(Uri.parse(url))
.setDomainUriPrefix("travellersystems.page.link/")
.setAndroidParameters(DynamicLink.AndroidParameters.Builder("com.client.traveller").build())
.setIosParameters(
DynamicLink.IosParameters.Builder("com.example.ios")
.setAppStoreId("123456789")
.setMinimumVersion("1.0.1")
.build())
.buildDynamicLink()
Log.e(javaClass.simpleName, dynamicLink.uri.toString())
val actionCodeSettings = ActionCodeSettings.newBuilder()
.setUrl(url)
.setAndroidPackageName("com.client.traveller", true, null)
.setHandleCodeInApp(true)
.setDynamicLinkDomain("travellersystems.page.link")
.build()
user?.sendEmailVerification(actionCodeSettings)
?.addOnCompleteListener{task ->
if (task.isSuccessful){
Log.e(javaClass.simpleName, "sendEmailVerification successful")
}
else{
Log.e(javaClass.simpleName, task.exception?.localizedMessage)
}
}
}
Here i'm trying get some data
private fun getDynamicLinks(){
FirebaseDynamicLinks.getInstance()
.getDynamicLink(intent)
.addOnSuccessListener(this){ pendingDynamicLinkData ->
Log.e(javaClass.simpleName, pendingDynamicLinkData?.toString() ?: intent.dataString+"")
var deepLink: Uri? = null
if (pendingDynamicLinkData != null){
deepLink = pendingDynamicLinkData.link
viewModel.setEmailVerified()
Dialog.newInstance(getString(R.string.post_email_verification)).show(this.supportFragmentManager, "Weryfikacja e-mail")
}
}
.addOnFailureListener {
Log.e(javaClass.simpleName, it.message)
}
}
Activiyt where I have getDynamicLinks in AndroidManifest:
<activity
android:name=".ui.home.HomeActivity"
android:theme="#style/AppTheme.StatusBar.Transparent">
<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:scheme="https"
android:host="travellersystems.page.link"
/>
</intent-filter>
</activity>
Can you say what I'm doing wrong?
Related
I'm making an App that will use the FreeSound API, and for making certain requests I need to authenticate via Oauth2. I'm using the AuthApp Library for this purpose. I get the authorization process done, here's the code:
#Composable
fun LoginScreen(viewmodel: LoginViewModel = hiltViewModel(), context: Context) {
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val data = result.data
data?.let {
val resp = AuthorizationResponse.fromIntent(it)
val ex = AuthorizationException.fromIntent(it)
}
}
Column(modifier = Modifier.fillMaxSize()) {
Button(onClick = {
val authService = AuthorizationService(context)
val authIntent = authService.getAuthorizationRequestIntent(viewmodel.authRequest)
launcher.launch(authIntent)
}) {
Text("Authorize")
}
}
}
And this is the part defined on the view model
private val serviceConfig = AuthorizationServiceConfiguration(
Uri.parse("https://freesound.org/apiv2/oauth2/logout_and_authorize/"), // authorization endpoint
Uri.parse("https://freesound.org/apiv2/oauth2/access_token/") // token endpoint
)
private val clientId = "my_client_id"
private val redirectUri: Uri = Uri.parse("https://freesound.org/home/app_permissions/permission_granted/")
private val builder = AuthorizationRequest.Builder(
serviceConfig,
clientId,
ResponseTypeValues.CODE,
redirectUri
)
val authRequest = builder.build()
This launches the custom tab properly and I get to make the authorization, but when it comes to listen to the deeplink, it just does nothing, here's how I have defined the manifest.
<activity
android:name="com.example.app.MainActivity"
android:exported="true"
android:label="#string/app_name"
android:theme="#style/Theme.MyApp">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="net.openid.appauth.RedirectUriReceiverActivity"
tools:node="replace"
android:exported="true">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"
android:host="freesound.org" android:path="/home/app_permissions/permission_granted"/>
</intent-filter>
</activity>
The redirect callback url defined on freesound is this "https://freesound.org/home/app_permissions/permission_granted/" it returns the code as a parameter on the url, but the app does not react, and I cannot change the callback from a url to a custom scheme.
This seems like a package visibility issue as mentioned by Android
https://developer.android.com/about/versions/11/privacy/package-visibility
fun Activity.callPlayStoreIntent() {
val appPackageName = this.packageName
try {
val uri = Uri.parse("market://details?id=$appPackageName")
val intent = Intent(ACTION_VIEW, uri)
startActivity(intent)
} catch (exception: ActivityNotFoundException) {
try {
val uri = Uri.parse("https://play.google.com/store/apps/details?id=$appPackageName")
val intent = Intent(ACTION_VIEW, uri)
startActivity(intent)
} catch (e: Exception) {
e.printStackTrace()
}
}
}
fun Context.callFromDialer(number: String) {
try {
val callIntent = Intent(Intent.ACTION_DIAL)
callIntent.data = Uri.parse("tel:$number")
if (callIntent.resolveActivity(packageManager) != null) {
startActivity(callIntent)
}
} catch (e: Exception) {
e.printStackTrace()
Toast.makeText(this, "No SIM Found", Toast.LENGTH_LONG).show()
}
}
fun Context.intentOpenMap(
latitude: Double,
longitude: Double,
label: String,
) {
try {
val uriBegin = "geo:$latitude,$longitude"
val query = "$latitude,$longitude($label)"
val encodedQuery = Uri.encode(query)
val uriString = "$uriBegin?q=$encodedQuery&z=20"
val uri = Uri.parse(uriString)
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
}
} catch (ex: Exception) {
ex.printStackTrace()
Toast.makeText(this, "Unable to open Map", Toast.LENGTH_LONG).show()
}
}
Your problem lies in the line of code intent.resolveActivity(getPackageManager()). When you call resolveActivity, you will get a warning like this:
Consider adding a declaration to your manifest when calling this method; see https://g.co/dev/packagevisibility for details
Check the document under PackageManager, you will see this note:
Note: If your app targets Android 11 (API level 30) or higher, the methods in this class each return a filtered list of apps. Learn more about how to manage package visibility.
So what does that mean?
In android 11, Google added package visibility policy. Apps now have tighter control over viewing other apps. Your application will not be able to view or access applications outside of your application.
What do you need to do?
All you need to do is add below line of code to AndroidManifest.xml:
<manifest>
<queries>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="geo" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="market" />
</intent>
<intent>
<action android:name="android.intent.action.VIEW" />
<data android:scheme="https" />
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
</intent>
</queries>
</manifest>
More information:
Package visibility in Android 11
Package visibility filtering on Android
I use Branch deep link in my android app with kotlin, I use the following link https://help.branch.io/developers-hub/docs/android-basic-integration
AndroidManifest.xml :
<application
android:name="net.app.activity.application"
android:allowBackup="false"
android:appComponentFactory="whateverString"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher"
android:supportsRtl="false"
android:theme="#style/AppTheme"
android:usesCleartextTraffic="true"
tools:replace="android:supportsRtl,android:allowBackup,android:appComponentFactory">
<activity android:name="net.app.activity.splash.SplashActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<data android:scheme="app" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
<!-- Branch App Links (optional) -->
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent
.category.BROWSABLE" />
<data android:scheme="https" android:host="app.test-app.link" />
<data android:scheme="https" android:host="app-alternate.test-app.link" />
</intent-filter>
</activity>
<meta-data
android:name="io.branch.sdk.BranchKey"
android:value="key...." />
<meta-data
android:name="io.branch.sdk.BranchKey.test"
android:value="key...." />
<meta-data
android:name="io.branch.sdk.TestMode"
android:value="false" />
I add Branch to My ApplicationClass.java :
// Branch logging for debugging
Branch.enableLogging();
// Branch object initialization
Branch.getAutoInstance(this);
I add Branch to my lancherActivity which is SplashActivity.kt as follows :
override fun onStart() {
super.onStart()
// Branch init
Branch.sessionBuilder(this).withCallback(branchListener).withData(this.intent?.data).init()
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
this.intent = intent
// Branch reinit (in case Activity is already in foreground when Branch link is clicked)
Branch.sessionBuilder(this).withCallback(branchListener).reInit()
}
object branchListener : Branch.BranchReferralInitListener {
override fun onInitFinished(referringParams: JSONObject?, error: BranchError?) {
if (error == null) {
Log.i("BRANCH SDK", referringParams.toString())
// Retrieve deeplink keys from 'referringParams' and evaluate the values to determine where to route the user
// Check '+clicked_branch_link' before deciding whether to use your Branch routing logic
} else {
Log.e("BRANCH SDK", error.message)
}
}
}
In my app,In one of my UI, A product with all details like name, quantity, price etc...I want to share this product, I create a share button, When I click on I choose "copied to press...",I copied the Url, then I paste it in the navigator, I want that the app will be opened in the app store But I didn't get this result.
Here's my code of sharing :
shareMerchant.setOnClickListener {
val image = merchant!!.logo
val url = this.getString(R.string.image_URL) + image
buo = Utility(this).prepareSharingLink(
merchant!!.id.toString(),
"store",
url,
UtilityTools.getInstance().getValue(merchant!!.name)
)
val lp = LinkProperties()
val message =
"Check out this store on App"
val ss = ShareSheetStyle(this, "Check this out!", message)
.setCopyUrlStyle(
resources.getDrawable(android.R.drawable.ic_menu_send, this.theme),
"Copy",
"Added to clipboard"
)
.setMoreOptionStyle(
resources.getDrawable(android.R.drawable.ic_menu_search, this.theme),
"Show more"
)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.EMAIL)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.MESSAGE)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.HANGOUT)
.setAsFullWidthStyle(true)
.setSharingTitle("Share With")
buo.showShareSheet(this, lp, ss, object : Branch.BranchLinkShareListener {
override fun onShareLinkDialogLaunched() {}
override fun onShareLinkDialogDismissed() {}
override fun onLinkShareResponse(
sharedLink: String?,
sharedChannel: String?,
error: BranchError?
) {
val metaData: java.util.HashMap<String, String> = java.util.HashMap()
if (error == null) {
metaData[Defines.Jsonkey.SharedLink.key] = sharedLink!!
} else {
metaData[Defines.Jsonkey.ShareError.key] = error.message
}
}
override fun onChannelSelected(channelName: String) {}
})
prepareSharingLink code as follows :
fun prepareSharingLink(
itemID: String,
itemType: String,
imageURL: String?,
customTitle: String = ""
): BranchUniversalObject {
val canonical = itemType.plus("/").plus(itemID)
val branchUniversalObject = BranchUniversalObject()
branchUniversalObject.canonicalIdentifier = canonical
branchUniversalObject.title = customTitle
branchUniversalObject.setContentDescription("")
branchUniversalObject.setContentImageUrl(imageURL!!)
branchUniversalObject.contentMetadata.customMetadata["itemType"] = itemType
branchUniversalObject.contentMetadata.customMetadata["itemID"] = itemID
branchUniversalObject.isLocallyIndexable
branchUniversalObject.isPublicallyIndexable
branchUniversalObject.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PRIVATE)
return branchUniversalObject
}
I want to know if I have an error or something missing in my code? And Why Branch Deep Link does not open with play store?
In my android app with kotlin language with IDE Android studio 4.0,
I want to share a product which have an image and some other information.
I use the Branch Sdk, I added a new module in my project.
In AndroidManifest.xml, I add the following instructions :
<meta-data android:name="io.branch.sdk.BranchKey" android:value="......" />
<intent-filter>
<data android:scheme="...app.link" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="...-app.link"
android:scheme="https" />
<!-- example-alternate domain is required for App Links when the Journeys/Web SDK and Deepviews are used inside your website. -->
<data
android:host="....test-app.link"
android:scheme="https" />
</intent-filter>
In my build.gradle, I added :
implementation project(path: ':Branch-SDK')
Let's move to kotlin code now, I add the following function :
fun prepareSharingLink(
itemID: String,
itemType: String,
imageURL: String?,
customTitle: String = ""
): BranchUniversalObject {
val canonical = itemType.plus("/").plus(itemID)
var branchUniversalObject = BranchUniversalObject()
branchUniversalObject.canonicalIdentifier = canonical
branchUniversalObject.title = customTitle
branchUniversalObject.setContentDescription("")
branchUniversalObject.setContentImageUrl(imageURL!!)
branchUniversalObject.contentMetadata.customMetadata["itemType"] = itemType
branchUniversalObject.contentMetadata.customMetadata["itemID"] = itemID
branchUniversalObject.isLocallyIndexable
branchUniversalObject.isPublicallyIndexable
branchUniversalObject.setContentIndexingMode(BranchUniversalObject.CONTENT_INDEX_MODE.PRIVATE)
return branchUniversalObject
}
And In the product activity, when I click on share button, I add the following code :
share.setOnClickListener {
val image = productData.mainImage
val url = this.getString(R.string.image_URL) + image
buo = Utility(this).prepareSharingLink(
productData.id.toString(),
"product",
url,
UtilityTools.getInstance().getValue(productData.name)
)
val linkProperties = LinkProperties()
val message =
if (UtilityTools.getIsAr()) "يرجى الاطلاع على هذا المنتج "
else "Check out this product"
val ss = ShareSheetStyle(this, "Check this out!", message)
.setCopyUrlStyle(
resources.getDrawable(android.R.drawable.ic_menu_send),
"Copy",
"Added to clipboard"
)
.setMoreOptionStyle(
resources.getDrawable(android.R.drawable.ic_menu_search),
"Show more"
)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.FACEBOOK)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.EMAIL)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.MESSAGE)
.addPreferredSharingOption(SharingHelper.SHARE_WITH.HANGOUT)
.setAsFullWidthStyle(true)
.setSharingTitle("Share With")
buo.showShareSheet(this, linkProperties, ss, object : Branch.BranchLinkShareListener {
override fun onShareLinkDialogLaunched() {}
override fun onShareLinkDialogDismissed() {}
override fun onLinkShareResponse(sharedLink: String?, sharedChannel: String?, error: BranchError?) {
Log.e("LinkShared", "success")
}
override fun onChannelSelected(channelName: String) {}
})
After all this, I couldn't sharing the product detail yet,
So, How can I use Branch sdk to share this product ? And where's the problem in my code ?
I have an advertisment in google adsense for my android application and i know that when user clicks on ads, google create the link with info about user for tracking. So i want to get that link and gclid parameter inside it. How can i do that?
I already tried to do it with intent and google play install referrer, but intent returns null, and google play install referrer returns empty string or sometimes FEATURE_NOT_SUPPORTED
This is my intent getting code:
val intent = this.intent
val uri = intent?.data
urlFromIntent = uri.toString()
Manifest:
<receiver android:name="com.google.android.gms.analytics.CampaignTrackingReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.android.vending.INSTALL_REFERRER" />
</intent-filter>
</receiver>
<service android:name="com.google.android.gms.analytics.CampaignTrackingService"
android:enabled="true"
android:exported="false" />
And my google play install referrer code:
mRefferClient = InstallReferrerClient.newBuilder(this).build()
mRefferClient.startConnection(object : InstallReferrerStateListener {
#SuppressLint("SwitchIntDef")
override fun onInstallReferrerSetupFinished(responseCode: Int) {
when (responseCode) {
InstallReferrerClient.InstallReferrerResponse.OK -> {
try {
if (BuildConfig.DEBUG) Log.d("InstallReferrerState", "OK")
var response = mRefferClient.installReferrer
urlFromReferClient = response.installReferrer
urlFromReferClient += ";" + response.referrerClickTimestampSeconds
urlFromReferClient += ";" + response.installBeginTimestampSeconds
mRefferClient.endConnection()
} catch (e: RemoteException) {
urlFromReferClient = e.toString()
}
}
InstallReferrerClient.InstallReferrerResponse.FEATURE_NOT_SUPPORTED -> {
urlFromReferClient = "FEATURE_NOT_SUPPORTED"
}
InstallReferrerClient.InstallReferrerResponse.SERVICE_UNAVAILABLE -> {
urlFromReferClient = "SERVICE_UNAVAILABLE"
}
}
}
override fun onInstallReferrerServiceDisconnected() {
// Try to restart the connection on the next request to
// Google Play by calling the startConnection() method.
}
})