i've tried to sending data between App1 to App2 via Intent in Android
i used this code but i couldn't resolve my problem.
App1 MainActivity :
Intent i2 = new Intent("com.appstore.MainActivity");
i2.setPackage("com.appstore");//the destination packageName
i2.putExtra("Id", "100");
startActivity(i2);
App2 MainActivity :
Bundle data = getIntent().getExtras;
if(data!=null){
String myString = b.getString("Id");
}
Manfiest App2 MainActivity:
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND_MULTIPLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
Final code:
App 1 :
Intent intent = new Intent();
intent.setClassName("com.appstore", "com.appstore.MyBroadcastReceiver");
intent.setAction("com.appstore.MyBroadcastReceiver");
intent.putExtra("KeyName","code1id");
sendBroadcast(intent);
App 2:
Reciver:
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "Data Received from External App", Toast.LENGTH_SHORT).show();
}
}
Manifest :
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="first_app_packagename" />
</intent-filter>
</receiver>
MainActivity :
MyBroadcastReceiver mReceiver = new MyBroadcastReceiver();
registerReceiver(mReceiver,
new IntentFilter("first_app_packagename"));
My requirement was to send the "user id" from App1 to App2 and get "username" back to App1.
I needed to launch my app directly without any chooser. I was able to achieve this using implicit intent and startActivityForResult.
App1 > MainActivity.java
private void launchOtherApp() {
Intent sendIntent = new Intent();
//Need to register your intent filter in App2 in manifest file with same action.
sendIntent.setAction("com.example.sender.login"); // <packagename.login>
Bundle bundle = new Bundle();
bundle.putString("user_id", "1111");
sendIntent.putExtra("data", bundle);
sendIntent.setType("text/plain");
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(sendIntent, REQUEST_CODE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (resultCode == Activity.RESULT_OK) {
Bundle bundle = data.getBundleExtra("data");
String username = bundle.getString("user_name");
result.success(username);
}
} else {
super.onActivityResult(requestCode, resultCode, data);
}
}
I had two activity in App2 ie. MainActivity and LoginActivity.
App2 > AndroidManifest.xml
<activity android:name=".LoginActivity">
<intent-filter>
<!--The action has to be same as App1-->
<action android:name="com.example.sender.login" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Sorry for this I had a little mix up with Java and Kotlin. My second app was in Kotlin, not that it will effect in any way.
App2 > LoginActivity.java
override fun onResume() {
super.onResume()
var userId = "No data received"
val intent = intent
if (intent != null
&& intent.action != null
&& intent.action.equals("com.example.sender.login")
) {
val bundle = intent.getBundleExtra("data")
if (bundle != null) {
userId = bundle.getString("user_id")
userId = " User id is $userId"
}
}
tvMessage.text = "Data Received: $userId"
}
fun onClickBack(view: View) {
val intent = intent
val bundle = Bundle()
bundle.putString("sesion_id", "2222")
intent.putExtra("data", bundle)
setResult(Activity.RESULT_OK, intent)
finish()
}
When you do this:
Intent i2 = new Intent("com.appstore.MainActivity");
i2.setPackage("com.appstore");//the destination packageName
i2.putExtra("Id", "100");
startActivity(i2);
you are calling the single-argument constructor of Intent. In this constructor, the argument is interpreted as the Intent ACTION. You then set the package name in the Intent.
When you call startActivity() with this Intent, Android will look for an Activity that contains an <intent-filter> with the specified ACTION. There are no installed applications that have an Activity defined like this in the manifest:
<activity>
<intent-filter>
<action android:name="com.appstore.MainActivity"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
So Android will not be able to find and launch the Activity that you want.
As you want to specify explicitly the component that you want to use, instead of using the 1-argument Intent constructor, you should do this instead:
Intent i2 = new Intent();
i2.setClassName("com.appstore", "com.appstore.MainActivity");
i2.putExtra("Id", "100");
startActivity(i2);
Using setClassName() you provide the package name and the class name of the component that you want to launch.
This should work:
APP1
Intent i2 = new Intent();
i2.setComponent(new ComponentName(PACKAGE,ACTIVITY));//the destination packageName
i2.putExtra("Id", "100");
startActivity(i2);
APP2
String myString = getIntent().getStringExtra("Id");
Using Bundle.putSerializable(Key,Object); and Bundle.putParcelable(Key, Object);
the former object must implement Serializable, and the latter object must implement Parcelable.
Content providers:
Content providers are the standard interface that connects data in one process with code running in another process.
See Android Docs.
Content provider working demo here.
Related
I have added a custom URL scheme to my Android 4+ app to be able to deep link to some view/activity:
// AndroidManifest.xml
...
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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="myapp"/>
<data android:host="webservice"/>
</intent-filter>
</activity>
// MainActivity
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
if (uri.getScheme().equalsIgnoreCase("myapp") && uri.getHost().equalsIgnoreCase("webservice")) {
Intent settingsIntent = new Intent(MainActivity.this, WebServiceSettingsActivity.class);
startActivity(settingsIntent);
}
}
}
This works fine, when a link like myapp://webservice/something is used, my app is startet and the WebServiceSettingsActivity is shown.
BUT: When pressing the back button, the WebServiceSettingsActivity is shown again. It seem, that MainActivity is re-startet with the same intent as before and thus the settings are shown again...
This can be repeated indefinitely. How to solve this?
Your MainActivity is opening your WebServiceSettingsActivity, but you're never finishing the former. This leaves you with 2 choices:
Call this.finish(); immediately after calling startActivity(settingsIntent);
This will kill your MainActivity so that there is nothing to return to after finishing the WebServiceSettingsActivity.
2 (better). Open your WebServiceSettingsActivity with startActivityForResult() instead of startActivity(), and finish your MainActivity when, and only when, returning from your WebServiceSettingsActivity:
private static final int REQUEST_CODE_WEB = 1;
public void onCreate(Bundle savedInstance) {
...
if (...) {
startActivityForResult(settingsIntent, REQUEST_CODE_WEB);
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_WEB) {
finish(); // Or do whatever you want, such as load your main content
}
}
My question is how to start app A within app B that appears app A is within app B through deep linking?
In the first picture below, the Debug app appears as a separate app from Slack (new code, Firebase deep linking). In the 2nd picture, the Debug app appears to be within the Slack app (old code, Android deep linking). I want to use Firebase deep linking and show the Debug app within other apps (Slack, Gmail etc).
Can anyone please go through my code below and let me know how I can achieve this?
Old code, Android deep linking:
AndroidManifest
<activity
android:name=".activity.SplashScreenActivity"
android:screenOrientation="portrait"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "abc://flights” -->
<data
android:host="sales"
android:scheme="abc" />
<data
android:host="deals"
android:scheme="abc" />
</intent-filter>
</activity>
Activity:
Intent intent = new Intent(SplashScreenActivity.this, BottomNavBarActivity.class);
//Deep Linking Content
Uri deepLinkData = getIntent().getData();
if (deepLinkData != null) {
intent.putExtra(EXTRA_DEEP_LINK, deepLinkData.getHost());
}
startActivity(intent);
overridePendingTransition(R.anim.splash_fade_in, R.anim.splash_fade_out);
finish();
New Code, Firebase deep linking:
AndroidManifest:
<activity
android:name=".activity.SplashScreenActivity"
android:screenOrientation="portrait"
android:theme="#style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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="abc.app.goo.gl"
android:scheme="http"/>
<data
android:host="abc.app.goo.gl"
android:scheme="https"/>
</intent-filter>
</activity>
Activity:
FirebaseDynamicLinks.getInstance()
.getDynamicLink(getIntent())
.addOnSuccessListener(this, new OnSuccessListener<PendingDynamicLinkData>() {
#Override
public void onSuccess(PendingDynamicLinkData pendingDynamicLinkData) {
// Get deep link from result (may be null if no link is found)
Uri deepLink = null;
if (pendingDynamicLinkData != null) {
// Start the activity through intent, same as before.
}
}
})
.addOnFailureListener(this, new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.v(TAG, "Firebase deep link failure");
}
});
Its dependent on the app which sends the intent, for example whether they pass FLAG_ACTIVITY_NEW_TASK or not. I suspect the difference here is how Slack is handling the links - they may treat web URLs differently than other format ones (your old links have non-standard schemes).
Create a method openApp(), and call it accorrding to your need.
public void openAnApp()
{
Boolean flag=false;
try{
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
final PackageManager packageManager = getActivity().getPackageManager();
Intent intent1 = new Intent(Intent.ACTION_MAIN, null);
intent1.addCategory(Intent.CATEGORY_LAUNCHER);
List<ResolveInfo> resInfos = packageManager.queryIntentActivities(intent1, 0);
ActivityInfo activity = null;
//getting package names and adding them to the hashset
for(ResolveInfo resolveInfo : resInfos) {
System.out.println("apap="+resolveInfo.activityInfo.packageName);
if(resolveInfo.activityInfo.packageName.equals("your.app.packagename"))
{
flag = true;
activity = resolveInfo.activityInfo;
break;
}
}
if (flag) {
// final ActivityInfo activity = app.activityInfo;
final ComponentName name = new ComponentName(activity.applicationInfo.packageName,activity.name);
intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
intent.setComponent(name);
getActivity().startActivity(intent);
//startActivity(Intent.createChooser(intent , "Send image using.."));
} else {
Uri uri=Uri.parse("market://details?id=your.app.packagename");
Intent goToMarket=new Intent(Intent.ACTION_VIEW,uri);
try{
startActivity(goToMarket);
}catch(ActivityNotFoundException e){
Toast.makeText(getActivity(),"Couldn't launch the market",Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
Toast.makeText(getActivity(), "Something went wrong", Toast.LENGTH_LONG).show();
e.printStackTrace();
}
}
I want to develop app that doesn't have icon launcher. The app will run alarmscheduler which triggered when app is installed or phone is rebooted.
The problem is how can I open the activity since the app doesn't have intent filter like below:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
Is there a way to handle dial code such as ##4635*#*# to open the activity ?
or any other solutions are welcomed.
You can do it with two ways:
1) as answer by #KishuDroid
2) By define code in manifest
public class MySecretCodeReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.provider.Telephony.SECRET_CODE")) {
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
}
In manifest file
<receiver android:name=".MySecretCodeReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SECRET_CODE" />
<data android:scheme="android_secret_code" android:host="4635" />
</intent-filter>
</receiver>
Note:
In Second method you must have to dial *#*#your_code#*#* and dont need to press call button
But in first method you can customise your prefix or postfix of code. For example *#your_code# or **your_code##. but you need to press call button.
You have to use Broadcast Receiver...
public class OutgoingCallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
if(null == bundle)
return;
String phonenumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
Log.i("OutgoingCallReceiver",phonenumber);
Log.i("OutgoingCallReceiver",bundle.toString());
if(code.equals("#056700") {
intent.setComponent(new ComponentName("com.example", "com.example.yourActivity"));
And Your Android Manifest
<receiver android:name="com.varma.samples.detectcalls.receivers.OutgoingCallReceiver">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
Also, include the permission:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
I want to launch app using my own app but not by giving the package name, I want to open a custom URL.
I do this to start an application.
Intent intent = getPackageManager().getLaunchIntentForPackage(packageInfo.packageName);
startActivity(intent);
Instead of package name is it possible to give a deep-link for example:
"mobiledeeplinkingprojectdemo://product/123"
Reference
You need to define a activity that will subscribe to required intent filters:
<activity
android:name="DeepLinkListener"
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="host"
android:pathPattern="some regex"
android:scheme="scheme" />
</intent-filter>
</activity>
Then in onCreate of your DeepLinkListener activity you can access the host, scheme etc.:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent deepLinkingIntent= getIntent();
deepLinkingIntent.getScheme();
deepLinkingIntent.getData().getPath();
}
Perform check on path and again fire a Intent to take the user to corresponding activity. Refer data documentation for more help.
Now fire a Intent:
Intent intent = new Intent (Intent.ACTION_VIEW);
intent.setData(Uri.parse(DEEP_LINK_URL));
Don't forget to handle the exception. If there is no activity that can handle the deep link, startActivity will return an exception.
try {
context.startActivity(
Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse(deepLink)
}
)
} catch (exception: Exception) {
Toast.makeText(context, exception.localizedMessage, Toast.LENGTH_LONG).show()
}
Ok so I've been bangin away at my first Android app and the NFC has been very hit and miss. I'm able to successfully pickup on plain text type records, but when I switch over to try to pickup on uri records the phone's browser keeps opening rather than my app. I'm clueless at this point so here's what I got...
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http" android:host="google.com"/>
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<data android:mimeType="text/plain"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
When I read the tag, I get a new intent but it's action type is "MAIN". Is it just being relaunched? And if so why doesn't the text record do the same? I've tried multiple uri records and every time I get this behavior. Here is part of the java src.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent launchIntent = getIntent();
String action = launchIntent.getAction();
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
Log.i(tag, "MATCH!");
}
nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
tagDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
tagDetected.addDataScheme("http");
tagDetected.addDataAuthority("google.com", null);
filters = new IntentFilter[] { tagDetected };
techArray = new String[][] {
new String[] {
IsoDep.class.getName()
},
new String[] {
NfcB.class.getName()
},
new String[] {
Ndef.class.getName()
}
};
}
public void onResume(){
super.onResume();
nfcAdapter.enableForegroundDispatch(this, nfcPendingIntent, filters, techArray);
Intent launchIntent = getIntent();
String action = launchIntent.getAction();
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
Log.i(tag, "MATCH!");
} else if(action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
Log.i(tag, "TECH DISCOVERED");
} else if(action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
Log.i(tag, "TAG DISCOVERED");
}
Parcelable[] msg = launchIntent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
//byte[] payloadData = msg.getRecords()[0].getPayload();
//Log.i(tag, "NUM records = " + Integer.toString(msg.getRecords().length));
}
public void onPause() {
super.onPause();
nfcAdapter.disableForegroundDispatch(this);
}
Another interesting note is that when I don't include the list of technologies in the enableForegroundDispatch() call, then the app doesn't pickup any intents resulting from NFC at all (when trying to read uri records). Any ideas oh wise internet?!
With ForegroundDispatch enabled, the intent will arrive through onNewIntent(), so you need to override that method in your activity to receive the NFC intent.
You also need to make sure that the hostname matches exactly. If the tag contains "www.google.com", your intent filter should contain the same name: <data android:scheme="http" android:host="www.google.com"/> and tagDetected.addDataAuthority("www.google.com", null).