In my app there is a WebView to which I load a website from server.
There are two cases:
On the loaded website there is a button which should lead to an another app. I know it can be handled like this:
Click me
but this doesn't work in the WebView (only in a standalone browser)! I tried to handle it in shouldOverrideUrlLoading and redirect to an external browser with Intent, but the URI with "intent://" URL is not recognised and cannot be opened.
The link I get from server is the 'intent' link.
The behaviour in both cases should be the same: if app is installed open the app, if not open Google Play do download the app.
Is there any way to do this?
I'm not sure if this is the best option, but I handeled it similarily to what #vineetv suggested. This method is called inside shouldOverrideUrlLoading():
private void handleNewUrl(String url) {
Uri uri = Uri.parse(url);
if (uri.getScheme().equals("http") || uri.getScheme().equals("https"))
openExternalWebsite(url);
else if (uri.getScheme().equals("intent")) {
String appPackage = getAppPackageFromUri(uri);
if (appPackage != null) {
PackageManager manager = getContext().getPackageManager();
Intent appIntent = manager.getLaunchIntentForPackage(appPackage);
if (appIntent != null) {
getActivity().startActivity(appIntent);
} else {
openExternalWebsite("https://play.google.com/store/apps/details?id=" + appPackage);
}
}
}
}
private String getAppPackageFromUri(Uri intentUri) {
Pattern pattern = Pattern.compile("package=(.*?);");
Matcher matcher = pattern.matcher(intentUri.getFragment());
if (matcher.find())
return matcher.group(1);
return null;
}
private void openExternalWebsite(String url) {
Intent webeIntent = new Intent(Intent.ACTION_VIEW);
webeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
webeIntent.setData(Uri.parse(url));
getActivity().startActivity(webeIntent);
}
It seems, to work. But if you have a better solution, let me know!
Related
Has anyone one worked on attaching GIFs in apps? Something similar to WhatsApp or Skype.
When I try to get the content uri from the below code -
final InputConnectionCompat.OnCommitContentListener callback = new InputConnectionCompat.OnCommitContentListener() {
#Override
public boolean onCommitContent(InputContentInfoCompat info, int flags, Bundle opts) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1 && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
try {
info.requestPermission();
} catch (Exception e) {
return false; // return false if failed
}
}
Log.d("TAG", "Content URI " + info.getContentUri());
return true; // return true if succeeded
}
};
return InputConnectionCompat.createWrapper(ic, info, callback);
}
This is what the content URI looks like, which works fine when passed to Glide.
Content URI (Swift keyboard) -> content://com.touchtype.swiftkey.fileprovider/share_images/Bi7V7tixYcLzbNgEJhE_NaXQ5eE.gif
Content URI(Gboard) -> content://com.google.android.inputmethod.latin.inputcontent/inputContent?fileName=%2Fdata%2Fuser_de%2F0%2Fcom.google.android.inputmethod.latin%2Ffiles%2Fgif69727604103223767740&packageName=com.testsdk&mimeType=image%2Fgif
But when same is passed to iOS app, then it will not work.
Can you please guide me in correct direction?
What needs to be sent to iOS app, so that same selected GIF can be shown in iOS app as well?
EDIT - I think I should use getLinkUri() instead of getContentUri().
Is it correct approach?
URI https://tse2.mm.bing.net/th?id=OGC.5e1a1b1d71e12b32cc7bfac93fbb7d1f&pid=Api&rurl=https%3a%2f%2fmedia.giphy.com%2fmedia%2fVe20ojrMWiTo4%2f200.gif&ehk=iHJHy%2fFSR7s2nIoEXxTIrUAWWuGBnz%2fecKwkM8Hm2ac%3d
I programmed an app that can send a message to twitter with an image attached. It works! I tested it on several devices and asked other people to do the same. It even works for a Direct Message when a twitter friend is selected. However, it does not work when "Direct Message" is selected. This forces the user to select a friend directly instead of selecting him via "Direct Message" (which is really strange) otherwise the picture is not attached. Just have a look at the screenshot:
Here is my Xamarin Android programming code. Let me know how to fix it. Currently, all options work, even selecting my friend but not "Direct Message". I also need to tell that I do not have any issue with the twitter text I expect to see in the tweet.
public bool TweetImage(Bitmap imageToTweet)
{
var messageIntent = context.FindMessageIntent(this.twitterConstants.PackageName);
if (messageIntent == null)
{
return false;
}
string outputFileBMP = SaveBitmap(imageToTweet);
context.Tweet(messageIntent, outputFileBMP, this.twitterConstants.DefaultTwitterText, this.twitterConstants.ChooserMessage);
return true;
}
and
public static Intent FindMessageIntent(this ContextWrapper contextWrapper, params string[] packageNames)
{
Intent wantedIntent = new Intent();
wantedIntent.SetType("text/plain");
var resolveInfos = contextWrapper.PackageManager.QueryIntentActivities(wantedIntent, PackageInfoFlags.MatchDefaultOnly);
var result = (from r in resolveInfos
from p in packageNames
where p == r.ActivityInfo.PackageName
select p).FirstOrDefault();
if (result != null)
{
wantedIntent.SetPackage(result);
return wantedIntent;
}
return null;
}
and
public static void Tweet(this ContextWrapper contextWrapper, Intent messageIntent, string filePath = null, string message = null, string chooserMessage = null)
{
if (filePath != null)
{
using (var file = new Java.IO.File(filePath))
{
messageIntent.PutExtra(Intent.ExtraStream, Android.Net.Uri.FromFile(file));
}
}
if (message != null)
{
messageIntent.PutExtra(Intent.ExtraText, message);
}
if (chooserMessage != null)
{
using (var chooser = Intent.CreateChooser(messageIntent, chooserMessage))
{
contextWrapper.StartActivity(chooser);
}
return;
}
contextWrapper.StartActivity(messageIntent);
}
Please note that I am using Android and need a solution based on Android (intent based).
Sadly, Twitter don't provide API access for uploading images via DM.
If you are able to use Twitter's private API, you should be able to attach a media_id to your DM. But other than that, you're out of luck.
Sorry.
Using Android 6.0.1, API 23,
I successfully implemented reading a file from a storage-location that the user picks in the document-picker of SAF (Storage Access Framework).
Now, I would like to use the Persist permissions that SAF allows in order to allow my App to always pick the same file (but without any document-picker window [and sub-windows] popping in all the time).
I somehow succeeded in implementing the Persist-permissions (as shown in the SAF-doc) (...for that, see my code example below...) - But questions came up:
In spite of persistence-permission working - why does the document-picker window keep popping up? Once the file is picked by the user - from this moment on - I would like to simply get the file content without any picker window coming to foreground. Is this possible? And if yes, how?
(I can tell that persistence permission is somehow working since the file gets read immediately without the user having to pick again. But still this nasty picker window should not have to come up - or does it?)
Is it possible to keep SAF persistence-permission even if my App gets closed or stopped? If yes, how?
Here is the code sample that does get the file content, including my trial with the persistence permission:
Inside a StorageClientFragment Class:
public String locationFileContent;
public void performFileSearch() {
Intent openDocumentIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
openDocumentIntent.addCategory(Intent.CATEGORY_OPENABLE);
openDocumentIntent.setType("text/plain");
openDocumentIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
| Intent.FLAG_GRANT_WRITE_URI_PERMISSION
| Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
startActivityForResult(openDocumentIntent, READ_REQUEST_CODE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (requestCode == READ_REQUEST_CODE && resultCode == Activity.RESULT_OK) {
Uri uri = null;
if (resultData != null) {
uri = resultData.getData();
// Here is my Persist-permission trial !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
getActivity().getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
this.locationFileContent = readTextFromUri(uri);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private String readTextFromUri(Uri uri) throws IOException {
InputStream inputStream = getActivity().getContentResolver().openInputStream(uri);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
stringBuilder.append(line);
}
inputStream.close();
return stringBuilder.toString();
}
Creating the Fragment gets done in MainActivity:
StorageClientFragment storageClientFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (getSupportFragmentManager().findFragmentByTag(FRAGTAG) == null ) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
storageClientFragment = new StorageClientFragment();
transaction.add(storageClientFragment, FRAGTAG);
transaction.commit();
}
}
Calling the FileSearch is done when a Test-Button is clicked:
public void TestingButtonClicked(View view) {
this.storageClientFragment.performFileSearch();
String stringFileContent = this.storageClientFragment.locationFileContent;
Toast.makeText(this, "Back in Main, Content = " + stringFileContent, Toast.LENGTH_SHORT).show();
}
The above code works nicely. But again, how can I stop the SAF document-picker window from showing up all the time (even though persist permission is set)?
why does the document-picker window keep croping up ?
Presumably because you keep starting an ACTION_OPEN_DOCUMENT activity. If you do not want to ask the user to pick a document, do not start this activity.
I would like to simply get the file content without any picker-window coming to foreground. Is this possible ? And if yes, how ??
The same way that you got the content originally: pass the Uri to openInputStream() on a ContentResolver.
If you are using takePersistableUriPermissions() to aim for long-lived access to the content, it is still your job to hold onto the Uri. This is not significantly different than how this sort of thing works in other environments (e.g., remembering the user's history of local file paths for a desktop OS program).
Since a Uri can be trivially converted to and from a String, saving the Uri somewhere (database, SharedPreferences, or other file) is not especially difficult.
Is it possible to keep SAF persistance-permission even if my App gets closed or stopped ? If yes, how ??
takePersistableUriPermission(), as you have already implemented.
I have implemented both chrome custom tab and webview for a website in android studio. They are both working fine. Now what I want is that if the user doesn't have chrome installed or has a chrome version less than 45 (minimum version needed for chrome custom tab), then open webview class. How to check the chrome version or whether chrome is installed or not? Here is the code snipet to open chrome custom tab by default
You should try to bind to the service and if it fails then you can fallback to the webview. You can see it here: https://github.com/GoogleChrome/custom-tabs-client/blob/cc6b8b9169ed7e70484bbdbbf39b672d1c4b3c80/Application/src/main/java/org/chromium/customtabsclient/MainActivity.java#L147
taken from https://github.com/GoogleChrome/custom-tabs-client/blob/master/demos/src/main/java/org/chromium/customtabsdemos/CustomTabActivityHelper.java:
public void bindCustomTabsService(Activity activity) {
if (mClient != null) return;
String packageName = CustomTabsHelper.getPackageNameToUse(activity);
if (packageName == null) return;
mConnection = new ServiceConnection(this);
CustomTabsClient.bindCustomTabsService(activity, packageName, mConnection);
}
you can check if 'packageName' is null
I have used the following code for my own purpose to check the chrome version with whether chrome is installed or not. Hope it will help, you should try.
String chromePackageName = "com.android.chrome";
int chromeTargetVersion = 45;
boolean isSupportCustomTab = false;
try {
PackageManager pm = getApplicationContext().getPackageManager();
List<PackageInfo> list = pm.getInstalledPackages(PackageManager.MATCH_DEFAULT_ONLY);
if (list != null && 0 < list.size()) {
for (PackageInfo info : list) {
if (chromePackageName.equals(info.packageName)) {
String chromeVersion = pm.getPackageInfo(chromePackageName, 0).versionName;
if(chromeVersion.contains(".")) {
chromeVersion = chromeVersion.substring(0, chromeVersion.indexOf('.'));
}
isSupportCustomTab = (Integer.valueOf(chromeVersion) >= chromeTargetVersion);
break;
}
}
}
} catch (Exception ex) {}
if (isSupportCustomTab) {
//Use Chrome Custom Tab
} else {
//Use WebView
}
I'm developing a Xamarin Android app and I need the ability to be able to work with Passes (PassKit passes for example (JSON)). I need to be able to list all the passes in a ListVew and be able to open and display the pass. Also be able to save them to a wallet such as PassWallet or Pass2u. I don't need the ability to create them, just view them, and save them to a wallet or discard them.
There seems to be an example Xamarin iOS app which does exactly what i need here but of course I need to be able to do this in Xamarin Android.
I've been researching this for hours but don't know how to achieve what i need. JSON.net seems the way to go to read the passes, but that's as far as I've managed to get. Some examples would be great. Can anybody help?
To add the pass into PassWallet you can use the following:
private static boolean launchPassWallet(Context applicationContext, Uri uri, boolean launchGooglePlay) {
if (null != applicationContext) {
PackageManager packageManager = applicationContext.getPackageManager();
if (null != packageManager) {
final String strPackageName = "com.attidomobile.passwallet";
Intent startIntent = new Intent();
startIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startIntent.setAction(Intent.ACTION_VIEW);
Intent passWalletLaunchIntent = packageManager
.getLaunchIntentForPackage(strPackageName);
if (null == passWalletLaunchIntent) {
// PassWallet isn't installed, open Google Play:
if (launchGooglePlay) {
String strReferrer = "";
try {
strReferrer = "&referrer=" + URLEncoder.encode(uri.toString(), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
strReferrer = "";
}
try {
startIntent.setData(Uri.parse("market://details?id=" + strPackageName + strReferrer));
applicationContext.startActivity(startIntent);
} catch (android.content.ActivityNotFoundException anfe) {
// Google Play not installed, open via website
startIntent.setData(Uri.parse("http://play.google.com/store/apps/details?id=" + strPackageName + strReferrer));
applicationContext.startActivity(startIntent);
}
}
} else {
final String strClassName = "com.attidomobile.passwallet.activity.TicketDetailActivity";
startIntent.setClassName(strPackageName, strClassName);
startIntent.addCategory(Intent.CATEGORY_BROWSABLE);
startIntent.setDataAndType(uri, "application/vnd.apple.pkpass");
applicationContext.startActivity(startIntent);
return true;
}
}
}
return false;
}
And an example call is:
launchPassWallet(getApplicationContext(),Uri.parse("http://test.attidomobile.com/PassWallet/Passes/AttidoMobile.pkpass"), true);
You can also use a file:// URL if you have the file locally.
To display them in the list, you'd need to unzip the .pkpass file and then parse the JSON for the relevant fields.