I want to create a custom url scheme and the url should look like:
zf-moments://p1234567890
I define it in manifest as:
<data
android:host="*"
android:scheme="zf-moments" />
The problem is my activity is started on every link click. I guess the problem is with host but I want the host to be any. Probably the host is checked 1st, then the scheme. How to define the manifest so that only above links clicks open my app?
Thanks
Related
I need to know if there is a way to override deepLinking mechanism to take url based action. I actually need a way to figure out whether url has query parameter or not. (Assume url doesn't have prefix) If url has query parameter i'll run app if not will redirect user to the browser)
As quoted in the Android Developer Documentation,
<data>
Add one or more tags, each of which represents a URI format that resolves to the activity. At minimum, the tag must include
the android:scheme attribute.
You can add more attributes to further refine the type of URI that the activity accepts.
android:pathPrefix
This attribute can be used to differentiate between different URL's
For example the intent filter for the URL
http://www.example.com/endpoint1
would be
<intent-filter>
<data
android:host="www.example.com"
android:pathPrefix="/endpoint1"
android:scheme="http" />
</intent-filter>
android:pathPattern
This attribute can be used to specify a regular expression for the path pattern making it suitable for path with parameters.
For example for the URL
https://www.example.com/endpoint1?param=1
android:pathPattern=".param=."
I want to open my Android app for a specific link not for the specific host so that whenever user types the url in browser my app should be shown in Open With options.
I have already got success in opening my app from browser link.
For e.g:
If user types: www.abc.com app must not be shown in Open with options. But if user types or clicks www.abc.com/video app must be shown.
I have tried diffrent combination of following but none of them works.
<data android:pathPrefix="www.abc.com"
android:pathPattern=".*"
android:pathPrefix="/video/" android:scheme="http" />
It shows me my app even if I have typed abc.com in web browser. But what i want is that my application should only be visible if the user typed exact url i.e. www.abc.com/video
From Android docs:
Each of these attributes is optional, but they are not independent of each other: For an authority to be meaningful, a scheme must also be specified. For a path to be meaningful, both a scheme and an authority must be specified.
Then you should use:
android:scheme="http" android:host="www.abc.com" android:path="/video"
What i Understands after applying all the combinations of
<data android:pathPrefix="www.abc.com" android:pathPattern=".*" android:pathPrefix="/video/" android:scheme="http" />
is that:
1.) Browser throws intent for the url part before the /(slash) operator. For e.g:
If I write www.abc.com/terms, Browser will throw intent for www.abc.com. similary It will also check for www.abc.com/videos, www.abc.com/xyz, abc.com/, abc.com/videos and throws intent.
Now, Its our responsiblity to check other params in the incoming url and provide checks for the url we want to handle.
In my case, I have added check for second parameter videos if it contains, else show the home screen for the app.
i have an application which associates pdf files in my Manifest(via intent-filters), so when someone click on pdf link in the default browser i can execute that action with my app and download it with a progressbar. my question is, is it a way that i can associate other files but not "hard coded" in my manifest, but to let the user choose(or write) that file extention in preferences for example and i can add it dynamically from code. i know that probably this can be done with broadcast receiver but cant find any examples or simple code for that matter. ive seen preference menu like that in bsplayer settings .. but cant post image cuz dont have enough reputation.
I will try to explain more detailed my problem, because i think that there was some misunderstanding with the answer below.
i have an application which have the fallowing code in my manifest.
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.BROWSABLE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
<data android:host="*" />
<data android:pathPattern=".*\\.pdf" />
</intent-filter>
2.i launch my app which registers .pdf files with it. so next time i click on pdf link in my browser, a window pops up, making me choose with what application should i complete that action. if i choose my application, my main activity is launched, in which i use getIntent() and my app downloads the file using progressbar.
3.the problem is that i want to download and other files like that ie. jpg, png .. etc, but giving the user a choice which ones, or even making him write the extentions for the files he wants to download using my application if clicks on link somewhere that leads to that kind of files.
4.to make this thing happen, file extensions should be added dynamically in code somewow and not in manifest. i was looking some examples for broadcast receiver, since that class can use IntentFilter class, but cant really understand what i should be doing with it.
5.My main goal: starting my app, there is layout with some spinner or edit box. the user choose/writes some extension (.dwf). that extension is now registered with my app. if the next time the user browsing internet clicks on link which leads to .dwf file he could choose to continue the action with my app. and the file should be downloaded just like the .pdf
6.sry for my bad english and some help will be appreciated. also code ;)
boolean enabled=prefs.getBoolean(key, false);
int flag=(enabled ?
PackageManager.COMPONENT_ENABLED_STATE_ENABLED :
PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
ComponentName component=new ComponentName(MyActivity.this, TargetActivity.class);
getPackageManager()
.setComponentEnabledSetting(component, flag,
PackageManager.DONT_KILL_APP);
Depending upon your preference you can Disable the activity that handles the File type in your BOOT_COMPLETED Reciever. I Believe you will have to have different activities to handle different file types and then disable selectively
Is there a way to define some kind of handling mechanism in Android and iOS that would allow me to do intercept either of the following:
myapp:///events/3/
- or -
http://myapp.com/events/3/
I'd like to 'listen' for either the protocol or the host, and open a corresponding Activity / ViewController.
I'd like too if these could be as system wide as possible. I imagine this will be more of an issue on iOS, but I'd ideally be able to click either of those two schemes, as hyperlinks, from any app. Gmail, Safari, etc.
EDIT 5/2014, as this seems to be a popular question I've added much detail to the answer:
Android:
For Android, refer to Intent Filter to Launch My Activity when custom URI is clicked.
You use an 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>
this is attached to the Activity that you want launched. For example:
<activity android:name="com.MyCompany.MyApp.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" android:host="com.MyCompany.MyApp" />
</intent-filter>
</activity>
Then, in your activity, if not running, the activity will be launched with the URI passed in the Intent.
Intent intent = getIntent();
Uri openUri = intent.getData();
If already running, onNewIntent() will be called in your activity, again with the URI in the intent.
Lastly, if you instead want to handle the custom protocol in UIWebView's hosted within your native app, you can use:
myWebView.setWebViewClient(new WebViewClient()
{
public Boolean shouldOverrideUrlLoading(WebView view, String url)
{
// inspect the url for your protocol
}
});
iOS:
For iOS, refer to Lauching App with URL (via UIApplicationDelegate's handleOpenURL) working under iOS 4, but not under iOS 3.2.
Define your URL scheme via Info.plist keys similar to:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.yourcompany.myapp</string>
</dict>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
Then define a handler function to get called in your app delegate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
// parse and validate the URL
}
If you want to handle the custom protocol in UIWebViews hosted within your native app, you can use the UIWebViewDelegate method:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *urlPath = [request URL];
if (navigationType == UIWebViewNavigationTypeLinkClicked)
{
// inspect the [URL scheme], validate
if ([[urlPath scheme] hasPrefix:#"myapp"])
{
...
}
}
}
}
For WKWebView (iOS8+), you can instead use a WKNavigationDelegate and this method:
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
NSURL *urlPath = navigationAction.request.URL;
if (navigationAction.navigationType == WKNavigationTypeLinkActivated)
{
// inspect the [URL scheme], validate
if ([[urlPath scheme] hasPrefix:#"myapp"])
{
// ... handle the request
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
}
//Pass back to the decision handler
decisionHandler(WKNavigationActionPolicyAllow);
}
Update: This is a very old question, and things have changed a lot on both iOS and Android. I'll leave the original answer below, but anyone working on a new project or updating an old one should instead consider using deep links, which are supported on both platforms.
On iOS, deep links are called universal links. You'll need to create a JSON file on your web site that associates your app with URLs that point to parts of your web site. Next, update your app to accept a NSUserActivity object and set up the app to display the content that corresponds to the given URL. You also need to add an entitlement to the app listing the URLs that the app can handle. In use, the operating system takes care of downloading the association file from your site and starting your app when someone tries to open one of the URLs your app handles.
Setting up app links on Android works similarly. First, you'll set up an association between your web site(s) and your app, and then you'll add intent filters that let your app intercept attempts to open the URLs that your app can handle.
Although the details are obviously different, the approach is pretty much the same on both platforms. It gives you the ability to insert your app into the display of your web site's content no matter what app tries to access that content.
Original answer:
For iOS, yes, you can do two things:
Have your app advertise that it can handle URL's with a given scheme.
Install a protocol handler to handle whatever scheme you like.
The first option is pretty straightforward, and described in Implementing Custom URL Schemes. To let the system know that your app can handle a given scheme:
update your app's Info.plist with a CFBundleURLTypes entry
implement -application:didFinishLaunchingWithOptions: in your app delegate.
The second possibility is to write your own protocol handler. This works only within your app, but you can use it in conjunction with the technique described above. Use the method above to get the system to launch your app for a given URL, and then use a custom URL protocol handler within your app to leverage the power of iOS's URL loading system:
Create a your own subclass of NSURLProtocol.
Override +canInitWithRequest: -- usually you'll just look at the URL scheme and accept it if it matches the scheme you want to handle, but you can look at other aspects of the request as well.
Register your subclass: [MyURLProtocol registerClass];
Override -startLoading and -stopLoading to start and stop loading the request, respectively.
Read the NSURLProtocol docs linked above for more information. The level of difficulty here depends largely on what you're trying to implement. It's common for iOS apps to implement a custom URL handler so that other apps can make simple requests. Implementing your own HTTP or FTP handler is a bit more involved.
For what it's worth, this is exactly how PhoneGap works on iOS. PhoneGap includes an NSURLProtocol subclass called PGURLProtocol that looks at the scheme of any URL the app tries to load and takes over if it's one of the schemes that it recognizes. PhoneGap's open-source cousin is Cordova -- you may find it helpful to take a look.
For the second option in your question:
http://myapp.com/events/3/
There was a new technique introduced with iOS 9, called Universal Links which allows you to intercept links to your website, if they are https://
https://developer.apple.com/library/content/documentation/General/Conceptual/AppSearch/UniversalLinks.html
On my application I am trying to make it so that it opens a activity when someone clicks a link on the browser. I am using this data block but it wont work.
<data android:scheme="http"
android:host="www.test.com"
android:pathPrefix="/get/"
android:pathPattern="/.*\\" />
For example when I click on www.test.com it opens the app when it should only open it when the pathPrefix is /get/. How can I fix this?
API: http://developer.android.com/guide/topics/manifest/data-element.html#path
So you have the prefix as /get but from my understanding of the documentation this is checked against the beginning of the string so it's irrelevant here.
Why it's catching all is this because your regex catches all?
Try something like:
android:pathPattern="[get]"