I'm at a loss for getting my application to register with epub files on a mobile device. I have a set of intent filters in my android manifest, but it still will not open with epub files on the sd card. When I go through the File Explorer app, it shows the file, but when I click on it, it says "The system does not support this type of file:". When I download a file from the internet, and then navigate to the download folder using the downloads application, the file does not show up at all (even though it's in the download folder in the file browser). I've also tried to get epub files to show up with the file chooser intent (Intent.ACTION_OPEN_DOCUMENT), but no luck. I'm guessing the last two do not show up because the intent loads with Intent.CATEGORY_OPENABLE
I've tried multiple epub files and all without success.
Can someone help figure out what I'm missing?
Using KitKat and higher phones.
Note: this does work with downloading from the internet. If I go to an epub link, this works, but not from the filesystem.
<!-- Open File Types -->
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:host="*" android:scheme="file"/>
<data android:pathPattern=".*\\.epub"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:host="*" android:scheme="file" android:mimeType="text/plain"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="file"/>
<data android:mimeType="application/epub+zip"/>
</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="*" android:scheme="http"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="http" android:mimeType="text/plain"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="http"/>
<data android:mimeType="application/epub+zip"/>
</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="*" android:scheme="https"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="https" android:mimeType="text/plain"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="https"/>
<data android:mimeType="application/epub+zip"/>
</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="*" android:scheme="content"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="content" android:mimeType="text/plain"/>
<data android:pathPattern=".*\\.epub"/>
</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="*" android:scheme="content"/>
<data android:mimeType="application/epub+zip"/>
</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="*" android:scheme="book"/>
</intent-filter>
<intent-filter
android:icon="#raw/icon"
android:label="ePub File"
android:priority="1" >
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:scheme="https" />
<data android:scheme="ftp" />
<data android:scheme="file" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.epub" />
</intent-filter>
Update:
Looking for answers to the following questions for the bounty:
How do I get android system to recognize that epub files on internal or external storage can be opened with my app?
How do I get the default file browser (Storage Access Framework) to show epub files?
How do I get android system to recognize that epub files on internal or external storage can be opened with my app?
The "android system" does not have much to do with it, particularly today.
Support in MimeTypeMap (or, more accurately, libcore.net.MimeUtils from the framework classes) for .epub/application/epub+zip was added ~35 hours ago. Presumably, it will show up in a future edition of Android. Prior to that, the only file managers that will use that MIME type are ones that added it in themselves.
At a high level, when confronted with a problem like this, the solution is fairly simple:
Find another app that does what you want (in this case, another EPUB reader)
Use the App Browser app to see what that app's manifest looks like and what it chose for <intent-filter> stanzas
In general, I usually see an <intent-filter> with a scheme and a MIME type or a scheme, host, and path stuff. Having the MIME type and the path stuff is unlikely to help, as if the Intent does not explicitly have the MIME type in it, and Android doesn't know about mapping that specific extension to your MIME type, your <intent-filter> may not match.
Also, you will need to test with multiple "File Manager" apps, as Android does not have a file manager, and therefore you may be experiencing bugs/limitations in the one that you are testing.
How do I get the default file browser (Storage Access Framework) to show epub files?
Specify the proper MIME type and pray for a miracle.
Again, until Android itself offers a bit more built-in support for mapping .epub to the MIME type, you are reliant upon storage providers themselves happening to know that .epub maps to the application/epub+zip MIME type. Some providers will, because they are getting that information from some back-end server that may know more MIME types than does Android itself. Some providers may not, such as Android's MediaStore-backed provider of what's on external storage, as I doubt that MediaStore has its own local support for EPUB files.
Related
I have to filter two URL for an activity. I'm using Deep Links to App Content by specifying a url for the Deep Link Screen.
These are my urls
appdemo://deeplink
native://
I'm already added these two scheme to my Android Manifest file, looks like
<data android:scheme="appdemo" android:host="deeplink" />
<data android:scheme="native" />
my question is that, by providing scheme and host on the Android Manifest file, native:// this link does not work. it requires the android:host name also
(native://deeplink).
It is mandatory to specify the "android:host" for all url in android?
If no, how can i specify the different scheme.
The idea beside deep links is to use the same structure as normal links:
scheme://host/path
The main benefit is that you can teach your app even to open some Internet links, e.g. to open youtube (Android will ask, if you want to open in browser or YouTube app or your app):
<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="http"/>
<data android:scheme="https"/>
<data android:host="youtube.com"/>
<data android:host="www.youtube.com"/>
<data android:host="m.youtube.com"/>
<data android:host="youtu.be"/>
<data android:pathPattern=".*"/>
</intent-filter>
So, answering your questions:
Yes, it is mandatory to specify both scheme and host.
A good practice of handling two different links in one activity is to use different paths. Like this:
<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="appdemo" android:host="deeplink" android:pathPrefix="/path1/"/>
</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="appdemo" android:host="deeplink" android:pathPrefix="/path2/"/>
</intent-filter>
Then you can get your path in onNewIntent:
Uri data = intent.getData();
String path = data == null ? null : data.getPath();
...and build some logic depending on this path.
The above answer is acceptable and, in my case i want to navigate a new activity through this intent filter, and i got some information to the above answer and made some changes in my code and fix the issue.
Also I'm not specifying the host name for my second intent.
<activity
android:name=".DeepLinkActivity"
android:exported="true"
android:screenOrientation="portrait"
android:theme="#style/AppTheme.Launcher">
<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="appdemo" android:host="deeplink" />
</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="native" />
</intent-filter>
</activity>
Now my both url navigate to DeepLinkActivity.
appdemo://deeplink
native://
Do you think this is not an optimized way?
Any other suggestions for that please mention.
How to setup intent filter for url with redirection?
https://mail.mailserverXXX.com/m/redirect?url=http://foosubdomain.foodomain.com/#object?id=e1162d22-222b-4522-2210-c222102d6022
This filter does not work for URL above.
<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="http"/>
<data android:scheme="https"/>
<data android:host="foosubdomain.foodomain.com"/>
</intent-filter>
This filter works for URL above. But this is not what needed. I need to filter by host in redirect part foosubdomain.foodomain.com
<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="http"/>
<data android:scheme="https"/>
<data android:host="mail.mailserverXXX.com"/>
</intent-filter>
Well bad news. After a long check I found that intent-filter doesnt even parse everything after question mark
In other words from link
https://mail.mailserverXXX.com/m/redirect?url=http://foosubdomain.foodomain.com/#object?id=e1162d22-222b-4522-2210-c222102d6022
Intent-filter works only with that part
https://mail.mailserverXXX.com/m/redirect
So there is impossible to write universal solution for your problem.
Well, I was breaking the hell of my brain cells with this and no solution came up...
Usually, in Android, to open the Web Browser in a specified Website, we do this:
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com"));
startActivity(browserIntent);
So, I got a Data URI Scheme (dunno if it is written this way, i'm not an expert on this kind of stuff) like this:
data:text/html;charset=utf8;base64,<base64 html code>
If I copy and paste this in a web browser, it will handle it the way I want it.
But how can I do it programatically in Android?
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(dataHTMLBase64));
startActivity(browserIntent);
dataHTMLBase64 stores the Data URI Scheme I mentioned before.
The code above won't work. It won't even launch chrome.
What can I do?
PS: I'm not good with English. Please warn me if I didn't express myself the right way...
Actually, it appears that one can launch a Data URI in an Android browser quite easily.
String url = "data:text/html;charset=utf8,<b>Hee-haw!</b>";
startActivity(Intent.makeMainSelectorActivity(
Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER)
.setData(Uri.parse(url.toString())));
Using apktool I reviewed the AndroidManifest.xml of the Google Chrome .apk file.
(apktool is quite easy to install, and then the command is simply apktool d example.apk)
I found the relevant intent filters (listed below) so there are many possible ways to launch the browser. Of course other browsers may have different intent filters, but it seems that APP_BROWSER is a good choice.
<activity-alias android:exported="true" android:name="com.google.android.apps.chrome.Main" android:targetActivity="org.chromium.chrome.browser.document.ChromeLauncherActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LAUNCHER"/>
<category android:name="android.intent.category.BROWSABLE"/>
<category android:name="android.intent.category.APP_BROWSER"/>
<category android:name="android.intent.category.NOTIFICATION_PREFERENCES"/>
</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="googlechrome"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:scheme="about"/>
<data android:scheme="javascript"/>
</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="googlechrome"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<data android:scheme="about"/>
<data android:scheme="content"/>
<data android:scheme="javascript"/>
<data android:mimeType="text/html"/>
<data android:mimeType="text/plain"/>
<data android:mimeType="application/xhtml+xml"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="multipart/related" android:scheme="file"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_SEARCH"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.speech.action.VOICE_SEARCH_RESULTS"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
</intent-filter>
<intent-filter>
<action android:name="com.sec.android.airview.HOVER"/>
</intent-filter>
<meta-data android:name="android.app.searchable" android:resource="#xml/searchable"/>
</activity-alias>
If you get these data URIs from somewhere you could do two things:
Parse the data content out of it and use it in some WebViewand call loadData(...) on it to display the contents
Save the data content of the URIs to some file, use FileProvider to make this file accessible outside of your app and use the URI returned by that to fire up a browser / view intent
I have a custom file extension like .foo that I want to associate my app with. I created this 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="file" android:pathPattern=".*\\.foo"/-->
<data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*\\.foo" android:host="*"/>
</intent-filter>
The problem is that this doesn’t work on some devices. For example, only the following works with the Samsung Galaxy S3 (Android version: 4.4.2):
<data android:scheme="file" android:mimeType="*/*" android:pathPattern=".*\\.foo" android:host="*"/>
However, with a LG G2 (Android version: 4.4.2), only this line works:
<data android:scheme="file" android:pathPattern=".*\\.foo"/>
To make it even worse, the Nexus 7 (Android-Version: 5.0) doesn’t seem to recognize custom file endings at all.
Has anyone ever had a similar problem and knows a solution?
Patterns for files are screwy... seems to be on purpose done by the developers.
It seems that the file pattern will work differently on different devices but it only depends on de depth of the file structure. See this link: pathPattern to match file extension does not work if a period exists elsewhere in the file name?
I think this way works for me (change "custom" with the extension you want to use) :
<activity android:name=".MainActivity">
<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="file"/>
<data android:mimeType="*/*"/>
<data android:pathPattern=".*\\.custom"/>
<!-- These additional pathPattern blocks are to allow for paths with
additional periods in them. See:
http://stackoverflow.com/questions/3400072/pathpattern-to-match-file-extension-does-not-work-if-a-period-exists-elsewhere-i/8599921 -->
<data android:pathPattern=".*\\..*\\.custom"/>
<data android:pathPattern=".*\\..*\\..*\\.custom"/>
<data android:pathPattern=".*\\..*\\..*\\..*\\.custom"/>
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.custom"/>
<data android:host="*"/>
</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="file"/>
<data android:pathPattern=".*\\.custom"/>
<data android:pathPattern=".*\\..*\\.custom"/>
<data android:pathPattern=".*\\..*\\..*\\.custom"/>
<data android:pathPattern=".*\\..*\\..*\\..*\\.custom"/>
<data android:pathPattern=".*\\..*\\..*\\..*\\..*\\.custom"/>
<data android:host="*"/>
</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:mimeType="application/vnd.ni.custom" android:scheme="file"/>
</intent-filter>
</activity>
I have an app which can play some videos, think MXPlayer plus a light browser. So I would like to get the opportunity to handle certain video files when someone clicks on a link in chrome of one those files, and also I would like to appear on the share popup of chrome when someone wants to share the link (so that my app may open the page). I have so far gotten my app to show up on the share popups of other apps but I just can not get it to show up on the share popup of Chrome. Here are my intent filters:
<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="http"/>
<data android:scheme="https"/>
<data android:mimeType="video/*"/>
<data android:mimeType="*/avi"/>
<data android:mimeType="*/mkv"/>
<data android:mimeType="application/mp4"/>
</intent-filter>
<intent-filter android:icon="#drawable/ic_launcher">
<action android:name="android.intent.action.SEND"/>
<data android:mimeType="*/*"/>
<data android:scheme="http"/>
<data android:scheme="https"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
Can someone tell me what I am doing wrong? Also I should mention I only want http/https streams, I do not want local files.
Thanks.
I managed to get it working by using this for the share menu option:
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:mimeType="text/plain"></data>
</intent-filter>
and this for when someone clicks on a link and chrome pops a dialog of where to open it:
<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="http"/>
<data android:scheme="https"/>
</intent-filter>