I have 2 links inside HTML code that is shown via a TextView. The first needs to open the URL in a webbrowser. The second needs to open another Activity in the App, so it must trigger some code in the App. Is this possible?
val textView = findViewById<TextView>(R.id.someTextView)
val html = "<ul>\n" +
"<li><a href=\\https://www.google.nl>Click here for google</a></li>\n" +
"<li><a href=\\scheme:open-something>Open App screen</a></li>\n" +
"</ul>\n"
textView.text = Html.fromHtml(html, Html.TO_HTML_PARAGRAPH_LINES_CONSECUTIVE)
TextView:
<TextView
android:id="#+id/someTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
I've used this post as a starting point.
val textView = findViewById<TextView>(R.id.someTextView)
val html = "<ul>" +
"<li><a href='myscheme://www.google.com'>link</a></li>" +
"<li><a href='myscheme://someuniquevalue.google.com'>link jim</a></li>" +
"</ul>"
textView.setText(Html.fromHtml(html))
textView.setMovementMethod(LinkMovementMethod.getInstance())
WebViewActivity:
class WebViewActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) {
val url = intent.dataString!!.replace("myscheme://", "https://")
val i = Intent(Intent.ACTION_VIEW)
i.data = Uri.parse(url)
startActivity(i)
}
}
}
Androidmanifest:
<activity android:name=".WebViewActivity" android:exported="false">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="myscheme" />
</intent-filter>
</activity>
Related
I have the following code
val pendingIntent = PendingIntent.getActivity(activity, 101,
Intent(activity,classType).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), PendingIntent.FLAG_IMMUTABLE)
val nfcIntentFilter = IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED)
val filters = arrayOf(nfcIntentFilter)
val TechLists = arrayOf(arrayOf(Ndef::class.java.name),
arrayOf(NdefFormatable::class.java.name))
nfcAdapter.enableForegroundDispatch(activity, pendingIntent, filters, TechLists)``
and in the activity I am trying to get the tag , action , message
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
val type: String? = intent.type
val action: String? = intent.action
}
However, action is already and tag is also null:
val tag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
it.getParcelableExtra(NfcAdapter.EXTRA_TAG,Tag::class.java)
} else {
it.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG)
}
In the manifest I have the following inside the activity tag:
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain"/>
</intent-filter>
I also have the permission enabled:
<uses-permission android:name="android.permission.NFC" />
Tried multiple codes and change the intent filter NDEF_DISCOVERED to TAG_DISCOVERD but everything failed. I have tested it also on three separate phones and also same issue. onNewIntent gets called but the intent does not provide information
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 ?