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
Related
I create Custom Intent as below.
Intent().also { intent ->
intent.setAction("STEP_COUNT_NOTIFICATION")
intent.putExtra("stepCount", todayTotalStepCount)
sendBroadcast(intent)
}
And I add this Custom Intent in my Broadcast Receiver tag of AndroidManifest.
<receiver
android:name=".BroadcastReceiver.BroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_DATE_CHANGED" />
<action android:name="com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION" />
</intent-filter>
</receiver>
Since I use two Intent, one is official intent and the other is custom, I need to distinguish received Intent.
onReceive function of BroadcastReceiver
override fun onReceive(context: Context?, intent: Intent?) {
val intentAction = intent!!.action
when (intentAction) {
Intent.ACTION_DATE_CHANGED -> {
// todayTotalStepCount = 0
var todayStepCountSet = hashMapOf<String, Int?>(
"todayStepCount" to 0
)
userDB
.document("$userId")
.set(todayStepCountSet, SetOptions.merge())
}
???? ->
}
}
How can I get STEP_COUNT_NOTIFICATION which is my custom intent?
First, create a public constant for your custom action:
companion object {
const val ACTION_STEP_COUNTER_NOTIFICATION = "com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION"
}
For your Intent, use the same action:
Intent().also { intent ->
intent.setAction(ACTION_STEP_COUNTER_NOTIFICATION)
intent.putExtra("stepCount", todayTotalStepCount)
sendBroadcast(intent)
}
Also, use the same action in your BroadcastReceiver:
override fun onReceive(context: Context?, intent: Intent?) {
val intentAction = intent!!.action
when (intentAction) {
Intent.ACTION_DATE_CHANGED -> {
// todayTotalStepCount = 0
var todayStepCountSet = hashMapOf<String, Int?>(
"todayStepCount" to 0
)
userDB
.document("$userId")
.set(todayStepCountSet, SetOptions.merge())
}
// Your custom action
ACTION_STEP_COUNTER_NOTIFICATION -> { // Add your code here }
}
}
Lastly, for AndroidManifest.xml:
<receiver
android:name=".BroadcastReceiver.BroadcastReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_DATE_CHANGED" />
// action should be the same as the value of ACTION_STEP_COUNTER_NOTIFICATION
<action android:name="com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION" />
</intent-filter>
</receiver>
action name should be the same for Intent, AndroidManifest.xml and BroadcastReceiver
Your Intent action needs to match the android:name for the corresponding <intent-filter>. Yours do not.
You have:
intent.setAction("STEP_COUNT_NOTIFICATION")
This has an action string of STEP_COUNT_NOTIFICATION.
You also have:
<action android:name="com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION" />
This has an action string of com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION.
Those two are not the same. They need to be the same. I recommend using com.chungchunon.chunchunon_android.STEP_COUNTER_NOTIFICATION in both places.
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
ActivityMain is singleTask.
I can use Code A to create a dynamic shortcuts icon in screen, it will show ActivityMain when I click the shortcuts icon.
You know I can also show ActivityMain by clicking the app icon.
How can I know a Activity lanuched from dynamic shortcuts when I use singleTask ?
BTW, Code B doesn't work.
Code A
#TargetApi(25)
private fun createShorcut() {
val sM = getSystemService(ShortcutManager::class.java)
val intent1 = Intent(this, ActivityMain::class.java)
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent1.setAction("My")
val shortcut1 = ShortcutInfo.Builder(this, "shortcut1")
.setIntent(intent1)
.setShortLabel("Shortcut 1")
.setLongLabel("Shortcut 2")
.setShortLabel("This is the shortcut 1")
.setDisabledMessage("Login to open this")
.setIcon(Icon.createWithResource(this, R.drawable.notify_icon))
.build()
sM.dynamicShortcuts = Arrays.asList(shortcut1)
}
#TargetApi(25)
private fun removeShorcuts() {
val shortcutManager = getSystemService(ShortcutManager::class.java)
shortcutManager.disableShortcuts(Arrays.asList("shortcut1"))
shortcutManager.removeAllDynamicShortcuts()
}
if (Build.VERSION.SDK_INT >= 25) {
createShorcut()
}else{
removeShorcuts()
}
<activity android:name=".ui.ActivityMain"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Code B
override fun onResume() {
super.onResume()
if (mActivity.intent.action.equals("My")) {
toast("ActivityMain from dynamic shortcuts")
}
}
Added Content:
To prateek: Thanks!
Do you mean I have to check it both onCreate and onNewIntent event when I use SingleTask?
In SingleTask:
A: When I run the APP (Click either App Icon or Shortcut Icon) for the first time, only onCreate event is fired.
B: If the app is already running, when I fire the App again (Click either App Icon or Shortcut Icon) , only onNewIntent event is fired.
So I have to check it both onCreate and onNewIntent event just like Code C, right?
Code C
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<Button>(R.id.btnClose).setOnClickListener {
finish()
}
createShorcut()
var which= this.intent.getBooleanExtra("yourkey", false)
displayResult(which)
}
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
var which= intent?.getBooleanExtra("yourkey", false)
displayResult(which?:false)
}
private fun displayResult(which:Boolean){
if (which) {
Toast.makeText(this, "From ShortCut Icon", Toast.LENGTH_LONG).show()
}else{
Toast.makeText(this, "From App Icon", Toast.LENGTH_LONG).show()
}
}
private fun createShorcut() {
val sM = getSystemService(ShortcutManager::class.java)
val intent1 = Intent(this, MainActivity::class.java)
intent1.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent1.setAction("My")
intent1.putExtra("yourkey", true)
val shortcut1 = ShortcutInfo.Builder(this, "ShortCut Item")
.setIntent(intent1)
.setShortLabel("Shortcut Item")
.setIcon(Icon.createWithResource(this, R.drawable.ic_launcher_foreground))
.build()
sM.dynamicShortcuts = Arrays.asList(shortcut1)
}
}
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
In my use case, I am adding a flag when creating intent to be launched via shortcut and always able to retrieve it at the other end.
Try something like .putExtra("fromShortcut", true). It should work.
Regarding retrieving action I haven't tried, sorry.
[Update]
This is how I am creating my intent object:
val shortcutIntent = Intent(context, YourActivity::class.java)
.setAction(Intent.ACTION_MAIN)
.putExtra("yourkey", true)
.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
)
and this is how you retrieve it at the receiving end:
mNewIntentReceived.getBooleanExtra("yourkey", false)
Also, I can observe you are not adding 'new task' flag in your intent, add that as well.
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.ACTION_DATE_CHANGED"/>
</intent-filter>
</receiver>
Manifests
var intent2 = Intent(requireActivity(), MyReceiver::class.java)
intent2.putExtra("Test", "value")
intent2.setAction(Intent.ACTION_DATE_CHANGED)
override fun onReceive(context: Context, intent: Intent) {
var st = intent.getStringExtra("Test")
if (intent.action.equals(Intent.ACTION_DATE_CHANGED)) {
var st = intent.getStringExtra("Test")
var toast = Toast.makeText(context, st, Toast.LENGTH_LONG) //
toast.show()
}
}
java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.DATE_CHANGED from pid=3604, uid=10091
I get an error like this
I searched but couldn't find a solution
Please help...
Try this.
You cannot use ACTION_DATE_CHANGED because it's a private android action, so you need to create your custom action.
<receiver
android:name=".MyReceiver"
android:exported="false">
<intent-filter>
<action android:name="${applicationId}.receiver.RECEIVE_MESSAGE_ACTION" />
</intent-filter>
</receiver>
Then you need to register for your activity before using it. Usually, I put in the onCreate method.
private fun registerReceiver(){
val filter = IntentFilter()
filter.addAction(MyReceiver.RECEIVE_MESSAGE_ACTION)
val customReceiver = MyReceiver()
registerReceiver(customReceiver, filter)
}
And when you called to share your message, use the following code.
companion object {
const val RECEIVE_MESSAGE_ACTION = "${BuildConfig.APPLICATION_ID}.receiver.RECEIVE_MESSAGE_ACTION"
}
private fun callCustomBroadcast(message: String) {
val intent = Intent(RECEIVE_MESSAGE_ACTION)
intent.putExtra("mymessage", message)
sendBroadcast(intent)
}
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?