With Crosswalk I had a very convenient javascript-to-app interface so I could call a java function from javascript and share data from my webapp to my android app.
How can I achieve this with Custom Tabs (or Trusted Web Activity) ?
There seems to be no way at all. There should be, especially when my app and my game/webapp are from the same author.
For example, I do not trust LocalStorage, especially now with Custom Tabs, it may get cleaned, or the user may uninstall the browser and install another one, so the saved data will be lost and the user will be angry at the app for the loss of the saved data, not even understanding that the data were in the browser, not in the app. So I used to have my webapps call the app to save datas.
Another example, when the Custom Tab uses Firefox instead of Chrome, then speech synthesis won't be available. I can detect it easily in my webapp. But I want my webapp to call the app and send it the words to pronounce. That is what I was doing with Crosswalk since it didn't support speech neither.
I understand that webviews are more appropriate for my use than Custom Tabs, but when the webview can't be used on a device (especially Android <5) then my app doesn't have a lot of other options than opening a Custom Tab instead (or Trusted Web Activity if available). I can't use Crosswalk anymore, it is discontinued and still full of serious bugs. And other solutions such as GeckoView or Alibaba Gcanvas are not ready.
edit:
In this article about Trusted Web Activity https://developers.google.com/web/updates/2017/10/using-twa I read
Nevertheless, you can coordinate with the web content by passing data
to and from the page in URLs (e.g. through query parameters, custom
HTTP headers, and intent URIs.)
edit:
I've been reading many pages, Intents and deep-linking are still obscure to me though, but here is what I tried.
I added an intent filter for a custom action :
<receiver android:name=".OutgoingReceiver" android:enabled="true">
<intent-filter>
<action android:name="custom_tabs_js_interface" />
</intent-filter>
</receiver>
I created a class for that receiver :
public class OutgoingReceiver extends BroadcastReceiver {
public static final String CUSTOM_INTENT = "custom_tabs_js_interface";
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received" , Toast.LENGTH_SHORT).show();
}
and I call it in javascript with
location.href="intent:#Intent;action=custom_tabs_js_interface;end";
I don't even pass data for now, I just try to call it.
but nothing happens...
Yes broadcast receiver doesn't work for some reason, probably security. But you can use an Activity in place of Broadcast Receiver to do this as below.
Use custom Android Intent Uri with custom host, query parameters, package, scheme and intent action. Invoke this intent uri from your javascript/html code. Example
"intent://myhost?key=value#Intent;scheme=myscheme;package=my.app.package;action=someaction;end"
Also declare an activity in the manifest file with intent filter to handle the specific host, scheme & action. Example
<activity android:name="my.app.package.ReceiverActivity">
<intent-filter>
<action android:name="someaction" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="myhost"
android:scheme="myscheme" />
</intent-filter>
</activity>
Now in the activity, handle the intent and extract the data from query parameters. Do whatever you want with the data and probably finish the activity in case you want to go back to the same screen. Example
public class ReceiverActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String value = getIntent().getData().getQueryParameter("key");
if (value != null) {
// value is basically your data
}
// in case you want to go back to same screen
finish();
}
}
And that is it. You have data for your disposal at an Android Activity. This ReceiverActivity could (preferrably) belong to same TWA app. Now from this Receiver Activity, you can easily send/share the data to any other apps. Hope this helps.
You can use a hybrid solution:
Use custom tabs as you want for game.
Your server can call your app when is needed using socket programming or push notifications to get the data you need to save in your app.
Also if sending data to your app is unsuccessful your game can warns user in browser at game.
Support for older android versions is encouraged as far as reasonably possible. Platform versions distribution (https://developer.android.com/about/dashboards/) at the moment this post was written states that you would lose around 12.7% of devices if you drop support for version 4.
Consider raising your minimum version to Lollipop where WebView was moved to an APK and use it. You will gain time and implementation simplicity since you'll be able to call #JavascriptInterface annotated methods while keeping your users engaged inside your app (https://developer.android.com/guide/webapps/webview_.
Related
We are doing an app for a client an he needs some similar functionality to this (see picture attached) offered by the iTranslate App on iOS.
With this functionality, when you are in any other App (for instance reading anything on the Medium App) and you select a word, a menu appears and you can select to open this word with the app of my client. But instead of opening the whole App and closing the one were are using, a kind of pop up appears:
I have a few questions about this:
- Does this have a name?
- Can something like this be done with Ionic or you need to code the app in Native?
- Is this possible only on iOS or also in Android?
I am really lost about this issue and would appreciate some guidance.
Thanks
The example in the first picture would be called a "Floating Context Menu," according to the Android Developers website. The example in the second picture would be called a "Popup Menu."
Hope this helps! Good Luck!
You can use a text selection toolbar https://material.io/design/platform-guidance/android-text-selection-toolbar.html# for this, which was added in Android 6.0. Note that you can only use this on Android 6.0 and later.
There is a nice article here, which provides some examples on how to create this:
https://medium.com/androiddevelopers/custom-text-selection-actions-with-action-process-text-191f792d2999
From the article, the basic implementation is the following:
AndroidManifest.xml
<activity
android:name=".ProcessTextActivity"
android:label="#string/process_text_action_name">
<intent-filter>
<action android:name="android.intent.action.PROCESS_TEXT" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
ProcessTextActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.process_text_main);
CharSequence text = getIntent()
.getCharSequenceExtra(Intent.EXTRA_PROCESS_TEXT);
// process the text
Intent intent = new Intent();
intent.putExtra(Intent.EXTRA_PROCESS_TEXT, result);
setResult(RESULT_OK, intent);
}
So, I am pretty sure you can implement this in ionic. I never wrote anything in ionic, but you may be able to call something like this Java code from it.
This is a customized PopupWindow(Android Documentation) which should not be a major issue to cook up with something like PopoverController (Iconic Documentation).
the real problem you will face is the text selection. you can look into this stackoverflow link for pointers.
Solutions like these may work in one or the other platform you have to muck the code unless there is and api for text selection in iconic.
if iconic does not give you the API you will have to roll up your sleeves. At this point you are on a slippery slope looking over the webview(s).
Update:
All the above juggling is needed to implement this within your app. Android and iOS will not allow you to add items to system context menu as you see in an PC based(Windows/MacOS/...) OS(s).
If you check Google Translator app in Android. it listens clipboard copy event and pops up a transient icon over other apps. in iOS drawing over other app is not possible.
So if you want your feature to show up in Medium App then they have to add the UI and they have to call your 'API'.
Summary
I am attempting to get data sent from the user via the Share menu. In this case, I'll use the basic Android web browser to select text and then share it to my app.
Problem
The first time the user shares the text my app gets the text as expected and displays it via Log.d() -- see the handleSendText() method in the code below.
However, each time thereafter even though the user has selected new text in the web browser and shared it with my app, I still get the original text the user selected (previous value).
Question
How do you reset the Intent -- or whatever it is -- so that I can obtain the new text the user has selected after the first time?
Details
My application has a MainActivity and I've followed the Google docs at :
http://developer.android.com/training/sharing/receive.html
With code like the following in my MainActivity
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent, "onCreate"); // Handle text being sent
}
}
}
#Override
public void onResume(){
super.onResume();
Intent intent = getIntent();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent, "onResume"); // Handle text being sent
}
}
}
void handleSendText(Intent intent, String callingMethodName) {
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (sharedText != null) {
Log.d("MainActivity", "sharedText : " + sharedText + " called from : " + callingMethodName);
}
}
}
My AndroidManifest section for the activity has the filter added like:
<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="text/plain" />
</intent-filter>
</activity>
Walk-Thru With Screens and Log
NOTE: Please notice that I've implemented the onResume() in my app also to insure that I don't only get the Intent when onCreate() is called (only one time when the app is started).
Start up browser and grab the text "hurricane".
Choose the app to share with (our test app).
View the log and notice that onCreate() and onResume() are called and value is 'hurricane'
Go back to browser again to share more text...
Select a new word, Atlantic, to share.
Extra note: When we click that Share link this time the Android MenuChooser doesn't display, instead, it automatically opens GrabText again. I found that behavior somewhat odd.
Notice that the Intent text still has the value of hurricane. You can see that there are now two new entries in the logcat.
Attempted Workaround Solutions
I have found that I can destroy the app entirely by overriding onPause() and calling finish() on my Activity (thus closing the entire app) and that seems to work, but isn't there some other way to reset that Intent or the associated text or something?
Do you know of any other way to insure that the new data is retrieved?
I appreciate any help.
UPDATE
Note:I'm updating because there's not a great way to show additional code tried, however, I wouldn't have know to try this without input from other SO User, CommonsWare.
The first answer I received was that I should add an #Override onNewIntent() so I added the following code to my MainActivity:
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("MainActivity", "onNewIntent()...");
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent, "onNewIntent"); // Handle text being sent
}
}
}
Upon adding that code and running and attempting the copy and then second copy of the new word, I still saw the following in logcat:
It doesn't even look as if the onNewItent() method is even called.
EDIT 2
I altered the emulator Settings...Developer Options... and turned off the "Don't keep activities" setting. It was previously turned on (checked).
After that, I ran the app which contains the onNewIntent() override but now it shows just the one onCreate() gone (which makes sense because the activity is still loaded) but still does not show the onNewIntent() call.
In this sample, I captured the word "remnants".
Edit 3
I built the app and created an APK and deployed it to my Samsung Galaxy Core Prime and I ended up with the same results. onNewIntent() is never called.
I just looked up onNewIntent in Google docs and it states:
onNewIntent(Intent intent) This is called for activities that set
launchMode to "singleTop" in their package, or if a client used the
FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent).
I haven't set singleTop so I will try it now. Hmm....
EDIT 4
I have now tried the singleTop variation. I was previously testing on API 15 (v4.0.4)on an emulator so I switched to API 21 (v5.0) to see if there'd be any different.
Here's what the addition of singleTop did to my AndroidManifest.xml:
<activity android:name=".MainActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Notice I also collapsed the two intent-filter nodes into the one.
Selected Text Did Change
On Android API Level 21 the Intent text was now coming in different each time I selected text in the browser.
onNewIntent Is Never Called
However, onNewIntent is NEVER called. I don't ever see it fire.
Share Menu Displayed Every Time
Also, now (on API 21) I see the Share menu every time I select text.
However, I also see an interesting thing when I switch to the browser. You can see multiple copies of the Activity in the list. What?!
Notice also that I implemented the MainActivity as a ListView (scrollable) so I could see the entries even without logcat (for running on real device). That made something else apparent: that the ListView was being updated on each newly shown Activity. But really, it should be the original Activity being appended to.
Creates Numerous GrabText Activities
Yes, now it creates a new GrabText Activity window each time I select text. I thought maybe that was because I had the singleTop set so I removed it but they still appear even after removing singleTop on API LEVEL 21.
Now that I saw it work -- provide different text each time on API 21 I decided to switch back to API Level 15 emulator and try it.
I will report back after I try some things back on API Level 15 again.
API Level 15 : Test Again
I started my other emulator running API Level 15 again and ran the app and even with singleTop set the value is never updated.
You can see this in the logcat and on the updated ListView:
You can also see that the code acts completely different, though I've not changed anything since it appends to the ListView of the one running Activity on api level 15.
I've written a book on this terribly documented thing. I hope this helps someone and that a Google Android dev sees this and explains it.
If your activity already exists, it will be called with onNewIntent() instead of onCreate(). onNewIntent() will be passed the Intent that you need to use for your message.
Try changing the android:launchMode of your activity in the manifest.xml to
singleTop
this way if the activity is already launched, new intents will be received in onNewIntent() method
There is only one answer that actually works, but it could cause other problems.
You just have to decide to call finish() whenever the Activity goes into onPause().
Here's the exact code I implemented which works on all API LEVELS.
#Override
public void onPause(){
super.onPause();
finish();
}
Destroy the Activity
When you add that code then every time you switch back to the app you are sharing from (the web browser in our case) then the onPause will fire on your MainActivity and the finish() method will set the Activity for destruction.
Share Menu Displayed Every Time After This
With this solution every time you select text from your sharing app (web browser) then the Share menu will be displayed and will display GrabText as one of the choices (instead of automatically forcing GrabText to the front again).
Shared Text Is Always the New Text
Since the MainActivity is completely destroyed it then has to be completely loaded (onCreate()) again and so it receives the new Intent text which was sent.
Not A Great Workaround
This isn't a great workaround however, because I believe dialog boxes in your app would also create onPause() to be called and your Activity would be destroyed. Obviously destroying your Activity onPause() just isn't great either because you are beginning to manage "memory" in a way that really should be left to the OS. However, in this case it seems to be the only way around the issue.
I am facing a problem in override the On Click Behavior in Appboy deeplink
Please find the following data
1- Register Appboy in BaseActivity which is the parent activity for all Application Activities
#Override
protected void onResume() {
AppboyInAppMessageManager.getInstance().registerInAppMessageManager(this);
Appboy.getInstance(this).requestInAppMessageRefresh();
}
#Override
protected void onPause() {
AppboyInAppMessageManager.getInstance().unregisterInAppMessageManager(this);
}
2- Add the receivers in Manifest File as following
<receiver android:name="com.forsale.forsale.appboy.AppboyGcmReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.forsale.forsale" />
</intent-filter>
</receiver>
<receiver
android:name="com.forsale.forsale.appboy.AppBoyOpenReceiver"
android:exported="false" >
<intent-filter>
<action android:name="com.forsale.forsale.intent.APPBOY_PUSH_RECEIVED" />
<action android:name="com.forsale.forsale.intent.APPBOY_NOTIFICATION_OPENED" />
</intent-filter>
</receiver>
Know I can send in app message using app boy dashboard, and receive the message, but when I click the message it open appboy web activity with the link
I need to override this behaviour to be able to get the link that I sent in In app message and parse some parameters from it and direct the use to an activity inside my app
I have tried the following
remove default app boy web activity from manifest file /// the app crash
implement the IInAppMessageManagerListener /// the app stop receiving any messages
Please note that the application call the onReceive method when trying to register appboy and print the log (action = REGISTRATION, RegId = "..."), but it never lo any other actions like RECEIVE, or OPEN
public void onReceive(Context context, Intent intent) {
AppboyLogger.i("AMIRA", String.format("Amira %s", intent.toString()));
String action = intent.getAction();
AppboyLogger.i("AMIRA", String.format("Amira %s", action));
Bundle bundle = intent.getExtras();
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
AppboyLogger.i("AMIRA", String.format("Amira %s", key + ":" + value.toString()));
}
}
The root of the problem is that we differentiate deep links and http links based on schema of the URI, so http (and some other schemes) links are detected as web links, and other formats are seen as deep links (see https://github.com/Appboy/appboy-android-sdk/blob/master/android-sdk-ui/src/com/appboy/ui/actions/ActionFactory.java).
We’ll consider how to instrument things for the use case you have, but in the meantime there’s a couple of ways you could solve the issue:
1) Create a deep link that is not also an http link. Everything should work if your link instead looks like, for example, forsale://mylink?a=b&2=3....etc.
2) Set a custom in-app message manager listener: https://documentation.appboy.com/Android/#in-app-message-customization. You can see an example of how we do this in our Droidboy sample app. In your case, you’d want to return defaults for everything but onInAppMessageButtonClicked and onInAppMessageClicked where you’d want to handle the link yourself if it’s of the format of your deep link. Your ticket indicates you’ve tried this, but I’d suggest starting with "the default one we create in the AppboyInAppMessageManager.java (#L608) in the Android SDK - and then just modifying the *clicked methods.
3) Download our UI code and modify the source. You could optionally download the Appboy Android SDK and modify the ActionFactory to handle your deep link in the way you want. Though, at the point you are going to do something like this, solution #2 is likely going to be a nicer one to implement and maintain.
Please let us know if one of these solutions works for you and if you have any other comments/questions.
Thanks,
Waciuma
Here's the use case: I want to create a statistics tool that lists all incoming push messages on a given phone, their message text, when they arrived and their source. clarification: I need 100% access to the data as I'm creating my own presentation tool for private use. It's not to be a consumer app.
I'm thinking I can achieve this by creating an app that somehow listens to all incoming intents of type com.google.android.c2dm.intent.RECEIVE and then analyzing the contents of those. Now I believe that is not possible with the security and intent model of stock Android. But is there anyway around this either with a stock rooted phone, or do I even have to go further and fork and modify AOSP?
Other options I can think of is to monitor the visual notification center itself, if that has an API (which I doubt).
Any suggestions are welcome. I am not intimidated by difficult tasks. Yet my knowledge is limited to Java Android coding - I know little of AOSP or the NDK, but I'd be willing to learn if this is the path I must take.
(Sorry if this is a very broad question, I'll accept the answer that gives me the easiest path to a solution)
So it turns out it wasn't all that difficult. You need an app with minSdkVersion=18 and then you can implement a NotificationListenerService which listens for created or deleted notifications, or you can poll for the currently visible.
Caveat: You need explicit persmission from the user to read notifications other than your own.
Basically what you do is 1. Extend the NotificationListenerInterface and override the onNotificationPosted like this:
#Override
public void onNotificationPosted(StatusBarNotification notif) {
Bundle extras = notif.getNotification().extras;
String packageName = notif.getPackageName();
if (extras != null) {
String title = "" + extras.getCharSequence(Notification.EXTRA_TITLE);
String description = "" + extras.getCharSequence(Notification.EXTRA_TEXT);
// Do whatever you want to do with the data
}
}
In addition you need to register the service in the manifest:
<application>
<!-- (...) -->
<service android:name=".YourListenerClassName"
android:label="#string/app_name" android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
</application>
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