Preconditions
1. App starts with LinkActivity, at this point we have no deep link intent, it's ok.
Main activity launched. There we are able to click the deep link.
By clicking on deep link opens LinkActivity, uri is correct, referringParams json is not empty (ok). But...
When we replaying step 2: uri is correct, but the reffering params are empty: "{}"; All other tries are with the same result.
Only when we pausing the app (for example switching to the recent apps menu) and then returning to the app - deep link works as expected, but only at first try. May be some issues with the session close (but in the current version of the sdk it self controls session close)
public class LinkActivity extends AppCompatActivity {
private static final String TAG = LinkActivity.class.getSimpleName();
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
}
#Override
protected void onStart() {
super.onStart();
Uri uri = getIntent().getData();
Log.w(TAG, "uri: " + uri);
Branch.getInstance().initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
Log.w(TAG, "json: " + referringParams);
startActivity(new Intent(LinkActivity.this, MainActivity.class));
}
}, uri, this);
}
}
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
public class BranchApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
Branch.enableLogging();
Branch.getAutoInstance(this);
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.test.myapp">
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:name=".BranchApplication"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".LinkActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<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:host="myapp.link"
android:scheme="https" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"/>
<meta-data
android:name="io.branch.sdk.BranchKey"
android:value="#string/branch_io_live_key" />
<meta-data
android:name="io.branch.sdk.BranchKey.test"
android:value="#string/branch_io_test_key" />
<meta-data
android:name="io.branch.sdk.TestMode"
android:value="false" />
</application>
</manifest>
implementation "io.branch.sdk.android:library:2.14.3"
Update:
Even with android:launchMode="singleInstance" for LinkActivity steel reproduces (I don't think this is the case).
Udpate2:
Bhardwaj mentioned that no need to call initSession when we initing Branch via getAutoInstance. But how to get refferingParams from uri in that case?
Update3:
From the Branch.checkIntentForSessionRestart doc:
Check for forced session restart. The Branch session is restarted if
the incoming intent has branch_force_new_session set to true. This is
for supporting opening a deep link path while app is already running
in the foreground. Such as clicking push notification while app in
foreground.
So, My desired behavior is matches this description. But how to force session restart?
You can try as mentioned below :-
Branch.getAutoInstance(this) -> Branch.getAutoInstance(this, true)
Branch.getInstance(context) -> Branch.getInstance()
Do not call initSession when you have getAutoInstance()
if(!initiatedBranchDeepLinks) {
// Configure Branch.io
initiatedBranchDeepLinks = true;
Branch branch = Branch.getInstance();
branch.initSession(new Branch.BranchReferralInitListener(){
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
if (error == null) {
// params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
// params will be empty if no data found
// ... insert custom logic here ...
String message = "Branch.io onInitFinished. Params: " + referringParams.toString();
Log.d(TAG, message);
} else {
Log.i(TAG, error.getMessage());
}
}
}, this.getIntent().getData(), this);
}
Here is Branch Test Bed app:
https://github.com/BranchMetrics/android-branch-deep-linking/tree/master/Branch-SDK-TestBed
You can use this as a reference and see what you are doing incorrectly.
This could be caused by your Manifest configuration. In your <activity> tag, you should include android:launchMode="singleTask". See this section of our docs. This may explain why you are receiving the parameters the first time, but not receiving them on a re-open.
Related
I'm currently trying to implement mollie payment into the flutter framework. For that I want to build a plugin in Java. So mollie has a very good documentation how to implement their API into an android app with Java. So the problem is when I hit the payment button in my app the browser opens with the correct checkout page. After the customer select his preferred payment method mollie goes back to my app, but I always get a empty query...
So this is my code for the flutter plugin
public class MolliePlugin implements MethodCallHandler, PluginRegistry.ActivityResultListener {
Activity activity;
Result activeResult;
Context context;
Intent intent;
boolean getData;
private static final int REQUEST_CODE = 0x1337;
MolliePlugin(Registrar registrar){
activity = registrar.activity();
}
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "mollie");
channel.setMethodCallHandler(new MolliePlugin(registrar));
}
#Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("startPayment")) {
activeResult = result;
String checkout = call.argument("checkoutUrl");
startPayment(checkout);
}
else {
result.notImplemented();
}
}
/// Start the browser switch with a ACTION_VIEW
void startPayment(String checkoutUrl) {
Intent browserIntent = new Intent(Intent.ACTION_VIEW,Uri.parse(checkoutUrl));
activity.startActivity(browserIntent);
}
So in the docs of mollie is written that I have to put the following code into the onCreate() function in my MainActivity:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
//...
Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
String paymentId = uri.getQueryParameter("id");
// Optional: Do stuff with the payment ID
}
}
So when I put this into the onCreate() in my MainActivity of my Flutter app I get always an ACTION_RUN back after I was routed back to my app. So I used the onNewIntent() function which gives me the correct action after coming back to my app (any ideas why?):
public class MainActivity extends FlutterActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
GeneratedPluginRegistrant.registerWith(this);
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("Action is: ",intent.getAction());
String paymentId = "No Id";
if (Intent.ACTION_VIEW.equals(intent.getAction()) && intent != null) {
Uri uri = intent.getData();
// This has no data...
Log.d("query ",intent.getDataString());
paymentId = uri.getQueryParameter("id");
// Optional: Do stuff with the payment ID
}
}
}
So here I get an empty query. the intent.getData() only returns my returnUrl which I have to set up in my AndroidManifest (see below). The returnUrl works fine but it has no data included after checking out and swichting back to the app...
My AndroidManifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.plugon.mollie_example">
<!-- io.flutter.app.FlutterApplication is an android.app.Application that
calls FlutterMain.startInitialization(this); in its onCreate method.
In most cases you can leave this as-is, but you if you want to provide
additional functionality it is fine to subclass or reimplement
FlutterApplication and put your custom class here. -->
<application
android:name="io.flutter.app.FlutterApplication"
android:label="mollie_example"
android:icon="#mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="#style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in #style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<data
android:host="payment-return"
android:scheme="molli" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>
</activity>
</application>
</manifest>
Any ideas what I'm doing wrong?
I want to implement deep linking for facebook app post.
Firstly I want to share my App content on Facebook Post and when user tap on the post then if User already has the app installed then open app otherwise It will open app link.
I follow https://developers.facebook.com/docs/applinks/android and https://developers.facebook.com/docs/sharing/android#linkshare but It's not working
how to share this data using LinkShare on facebook
target_url: "https://developers.facebook.com/android"
extras:
fb_app_id: [YOUR_FACEBOOK_APP_ID]
fb_access_token: "[ACCESS_TOKEN]"
fb_expires_in: 3600
To implement deep linking and sharing together, need to implement this feature using branch.io
Add dependency :
compile 'com.google.android.gms:play-services-appindexing:9.+'
Add this code in the manifest file inside Launcher Activity
<!-- Branch URI Scheme -->
<intent-filter>
<data android:scheme="androidexample" />
<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="example.app.link" />
<data android:scheme="https" android:host="example-alternate.app.link" />
</intent-filter>
Add this code to your Launcher Activity, You will get your link and data in this method
#Override
public void onStart() {
super.onStart();
// Branch init
Branch.getInstance().initSession(new Branch.BranchReferralInitListener() {
#Override
public void onInitFinished(JSONObject referringParams, BranchError error) {
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.i("BRANCH SDK", error.getMessage());
}
}
}, this.getIntent().getData(), this);
}
Add this code in MyApplication class
// Branch logging for debugging
Branch.enableLogging();
// Branch object initialization
Branch.getAutoInstance(this);
You can create deep link using this code
LinkProperties lp = new LinkProperties()
.setChannel("facebook")
.setFeature("sharing")
.setCampaign("content 123 launch")
.setStage("new user")
.addControlParameter("$desktop_url", "http://example.com/home")
.addControlParameter("custom", "data")
.addControlParameter("custom_random",
Long.toString(Calendar.getInstance().getTimeInMillis()));
buo.generateShortUrl(this, lp, new
Branch.BranchLinkCreateListener() {
#Override
public void onLinkCreate(String url, BranchError error) {
if (error == null) {
Log.i("BRANCH SDK", "got my Branch link to share: " + url);
}
}
});
refer this for Android
refer this for ios
I'm developing an audio streaming application for Android and integrating Android Auto. I've been following these two tutorials.
Android Developer Training
PTR Android Blog
Using the Desktop Head Unit, I'm able to select my media app from the media app list, but from there a ProgressBar stays instead of giving way to the "To play something, open the menu at the top left." message seen in the Universal Music Player.
On inspection, it seems that the MediaBrowserServiceCompat's onGetRoot()is never invoked and thus never populating my MediaItemCompat into the Auto app's list.
My manifest contains the following.
<manifest package="com.app.audio"
xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.MEDIA_CONTENT_CONTROL"/>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:name="com.app.audio.AudioApp"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme">
<activity
android:name="com.app.audio.presentation.home.HomeActivity"
android:label="#string/app_name"
android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name="com.app.audio.presentation.weather.WeatherActivity"
android:screenOrientation="userPortrait"/>
<activity android:name="com.app.audio.presentation.settings.SettingsActivity"/>
<activity android:name="com.app.audio.presentation.alarm.AlarmActivity"/>
<activity android:name="com.app.audio.presentation.sleep.SleepActivity"/>
<receiver android:name="com.app.audio.audio.AudioIntentReceiver">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON"/>
<action android:name="android.media.AUDIO_BECOMING_NOISY"/>
</intent-filter>
</receiver>
<receiver android:name="com.app.audio.presentation.alarm.AlarmReceiver"></receiver>
<receiver android:name="com.app.audio.presentation.sleep.SleepReceiver"></receiver>
<service
android:name="com.app.audio.data.service.media.MediaService"
android:exported="true">
<intent-filter>
<action android:name="android.media.browse.MediaBrowserService"/>
</intent-filter>
</service>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version"/>
<meta-data
android:name="com.google.android.gms.car.application"
android:resource="#xml/automotive_app_desc"/>
<meta-data
android:name="com.google.android.gms.car.notification.SmallIcon"
android:resource="#drawable/ic_launcher"/>
</application>
My automotive_app_desc.xml is very simple, only declaring Media.
<?xml version="1.0" encoding="utf-8"?>
<automotiveApp>
<uses name="media"/>
</automotiveApp>
My MediaService extends MediaBrowserServiceCompat. In the onCreate() I create and set my MediaSessionCompat.
#Override
public void onCreate() {
super.onCreate();
//...
mediaSession = new MediaSessionCompat(
this,
SESSION_TAG,
mediaIntentReceiver,
null
);
mediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
mediaSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public void onPlay() {
super.onPlay();
play(selectedStream);
}
#Override
public void onPause() {
super.onPause();
pause();
}
#Override
public void onStop() {
super.onStop();
stop();
}
#Override
public void onSkipToNext() {
super.onSkipToNext();
playNextStation();
}
#Override
public void onSkipToPrevious() {
super.onSkipToPrevious();
playPreviousStation();
}
});
mediaSession.setActive(true);
setSessionToken(mediaSession.getSessionToken());
updatePlaybackState(ACTION_STOP);
}
Finally, the two overridden methods from MediaBrowserServiceCompat, of which neither is ever called.
#Nullable
#Override
public BrowserRoot onGetRoot(#NonNull String clientPackageName, int clientUid, #Nullable Bundle rootHints) {
return new BrowserRoot(ROOT_ID, null);
}
#Override
public void onLoadChildren(#NonNull String parentId, #NonNull Result<List<MediaBrowserCompat.MediaItem>> result) {
List<MediaBrowserCompat.MediaItem> items = getMediaItemsById(parentId);
if (items != null) {
result.sendResult(items);
}
}
As far as I can tell, that's everything required to get an Android Auto started, yet when I open the app on my desktop head unit, there is only a ProgressBar greeting me, and when I open the off-screen nav drawer, there's another one. I haven't heard of that state in any material I've read. Is there something I missed?
Ultimately, the issue didn't have anything to do with what I described. The aforementioned MediaService also does other tasks that require a custom Binder. This custom Binder didn't call the onGetRoot() needed for the Head Unit. As a solution, I check the Intent action and return super.onBind() when it's from the MediaBrowserServiceCompat.
#Override
public IBinder onBind(Intent intent) {
if (SERVICE_INTERFACE.equals(intent.getAction())) {
return super.onBind(intent);
}
return new MediaBinder();
}
The SERVICE_INTERFACE is a constant in MediaBrowserServiceCompat.
I'm developing an Android auto but I have some problems in this part of my code, in Onbind method of the service:
public IBinder onBind(Intent arg0) {
Log.i("TAG", "OnBind");
// TODO Auto-generated method stub
if (SERVICE_INTERFACE.equals(arg0.getAction())) {
Log.i("TAG", "SERVICE_INTERFACE");
registerReceiver(receiver, filter);
return super.onBind(arg0);
} else {
Log.i("Musica Service", "musicBind");
return musicBind;}
}
I have other activities bound with my service through a musicBind IBinder, but on the other hand I have set all things to connect my app in Android auto interface but after close my app after disconnect the device from the android auto I can't stop my mediabrowserservice compat. I think it's due to this SERVICE_INTERFACE keeps binded the service. How can I stop or destroy this from the same servicemediabrowserservicecompat?
My application created files with a custom Mime type and stores them on Google Drive. The app can search and reopen these files just fine too. However, when I click the file in the Google Drive app (not my own app) the open flow does not work.
The Chooser Intent shows as expected with just my application listed, but when I select my application the Google Drive app briefly shows a downloading progress bar that never starts and then says there is an internal error.
My setup is below, I'm hoping somebody can tell me what causes this. although I would assume nothing is actually contacting my app by this point. The developer console has been filled in correctly as far as I know.
Manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="...">
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:icon="#drawable/logo" android:label="#string/app_name"
android:allowBackup="true" android:theme="#style/AppTheme">
<meta-data android:name="com.google.android.gms.version" android:value="#integer/google_play_services_version" />
<activity android:name=".MainActivity" android:label="#string/app_name"
android:launchMode="singleTop" android:theme="#style/AppTheme">
<meta-data android:name="com.google.android.apps.drive.APP_ID" android:value="id=..." />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="com.google.android.apps.drive.DRIVE_OPEN" />
<data android:mimeType="#string/app_mime" />
<data android:mimeType="#string/file_mime" /> <!-- matches the file im clicking -->
</intent-filter>
</activity>
</application>
Activity
public class MainActivity extends Activity {
private static final String ACTION_DRIVE_OPEN = "com.google.android.apps.drive.DRIVE_OPEN";
private static final String EXTRA_DRIVE_OPEN_ID = "resourceId";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
#Override
protected void onResume() {
super.onResume();
handleIntent();
}
private void handleIntent() {
Intent intent = getIntent();
if (ACTION_DRIVE_OPEN.equals(intent.getAction())) {
if (intent.getType().equals(getString(R.string.file_mime))) {
String fileId = intent.getStringExtra(EXTRA_DRIVE_OPEN_ID);
if (fileId != null && !"".equals(fileId)) {
...
} else {
Log.e(TAG, "Drive_Open has no valid file id - " + fileId);
}
} else {
Log.e(TAG, "Drive_Open called on the wrong mime type - " + intent.getType() + " found, " + getString(R.string.file_mime) + " required");
}
}
}
After some testing this seems to happen after there is a timeout between the drive app connecting to the server to retrieve information and passing it to the other app (or any other fault).
The initial problem will give you a meaningful error but then the drive app seems to maintain a cache or something which cases the above error to be displayed on all future attempts.
The solution is to either clear the data of both apps (which can be problematic) or (I found easier) re-install the app you are developing/testing. Either method stops this problem reoccurring.
My Android application uses Java OAuth library, found here for authorization on Twitter. I am able to get a request token, authorize the token and get an acknowlegement but when the browser tries the call back url to reconnect with my application, it does not use the URL I provide in code, but uses the one I supplied while registering with Twitter.
Note:
1. When registering my application with twitter, I provided a hypothetical call back url:http://abz.xyc.com and set the application type as browser.
2. I provided a callback url in my code "myapp" and have added an intent filter for my activity with Browsable category and data scheme as "myapp".
3. URL called when authorizing does contain te callback url, I specified in code.
Any idea what I am doing wrong here?
Relevant Code:
public class FirstActivity extends Activity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
OAuthAccessor client = defaultClient();
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(client.consumer.serviceProvider.userAuthorizationURL + "?oauth_token="
+ client.requestToken + "&oauth_callback=" + client.consumer.callbackURL));
startActivity(i);
}
OAuthServiceProvider defaultProvider()
{
return new OAuthServiceProvider(GeneralRuntimeConstants.request_token_URL,
GeneralRuntimeConstants.authorize_url, GeneralRuntimeConstants.access_token_url);
}
OAuthAccessor defaultClient()
{
String callbackUrl = "myapp:///";
OAuthServiceProvider provider = defaultProvider();
OAuthConsumer consumer = new OAuthConsumer(callbackUrl,
GeneralRuntimeConstants.consumer_key, GeneralRuntimeConstants.consumer_secret,
provider);
OAuthAccessor accessor = new OAuthAccessor(consumer);
OAuthClient client = new OAuthClient(new HttpClient4());
try
{
client.getRequestToken(accessor);
} catch (Exception e)
{
e.printStackTrace();
}
return accessor;
}
#Override
protected void onResume()
{
// TODO Auto-generated method stub
super.onResume();
Uri uri = this.getIntent().getData();
if (uri != null)
{
String access_token = uri.getQueryParameter("oauth_token");
}
}
}
// Manifest file
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".FirstActivity"
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"/>
</intent-filter>
</activity>
</application>
Twitter does not honor callbacks requested in OAuth requests (Twitter API Announce) and will only redirect to the callback URL specified in the Application Settings (note that "localhost" is not allowed).
I assume you checked Oauth-callback-on-android question.
Android guesswork--
After a bit of reading up, I see Android browser redirects MyApp:/// to your application and I'm guessing Twitter doesn't like this bespoke URI prefix. I'm no android developer but one suggestion I might make is to get "www.myapp.com" on the web and have a re-redirect there.
So have your OAuth return to http://www.myapp.com/redirect.aspx?oauth_token=abc and have that page redirect to myapp:///oauth_token=... (the desired result)
In my case, i have this working:
String authURL = m_provider.retrieveRequestToken (m_consumer, CALLBACK_URL);
And in the Manifest:
<activity android:configChanges = "keyboardHidden|orientation" android:name = "xxxx.android.xxxxx">
<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" android:host="tweet" />
</intent-filter>
In this case the callback url will be: myapp://tweet
It looks to me like you're doing the correct thing and Twitter is screwing up by always accepting your registered callback URL. Is there any way to change the registered URL? Maybe you could re-register and try an Android callback next time, see what happens.
My problem was that I was trying to log in with the same account I made the Twitter app. After I logged in with my personal profile the call back works (so far).