UiPath Platform: The Backend Engine Powering Your Automation - Session 1
Dueling Banjos: Inter-app Communication
1. Dueling Banjos
(Inter-App Communication)
Michael Dorin
Dan Ratcliff
Wednesday, March 20, 13 1
2. Agenda
• Introduction
• That was my Intent!
o Android Inter-App Communication
o Bound and Determined
• UR’all that… and more!
o iOS Inter-App Communication
• Android Security
• IoS Security
Wednesday, March 20, 13 2
3. Introduction
• Inter-application communication promotes
development of feature rich applications
• Developers leverage existing services to create
rich, ‘seamless’ applications
Wednesday, March 20, 13 3
4. Introduction
• Android and iOS provide messaging systems for
communications within and between applications
• These message systems also facilitate attacks
Wednesday, March 20, 13 4
5. Android Vocabulary
• Applications are...Built upon components
• Components
o Activity
o Service
o Broadcast Receiver
o Content Provider
• Inter-app communications
Wednesday, March 20, 13 5
6. Processes and Threads
• Application startup
• Android creates a 'Linux' process with a single
thread of execution
• You can (and probably will) create more than a
single thread of execution
• By default, all components of the same application
run in the same process
Wednesday, March 20, 13 6
7. Activity
Activity
System
Service Service
Component Data Paths
Wednesday, March 20, 13 7
8. That was my intent
• Intents launch activities and “Intents are system messages, running
services around the inside of the device, notifying
applications of various events, from
• Intents can hold data hardware state changes (e.g.,an SD card
was inserted), to incoming data (e.g., an
SMS message arrived),to application events
(e.g., your activity was launched from the
device’s main menu).”
http://android.programmerguru.com/android-
intent-example/
Wednesday, March 20, 13 8
9. Thats ‘intents’
• You may transmit Data in Intents
• You may return Data in Intents
• Implicit intents can launch a variety of activities
or services
• Explicit intents explicitly launch one particular
activity or service
Wednesday, March 20, 13 9
10. Intent Constructors
Intent()
Create an empty intent.
Creates an
Intent(String action) ‘implicit’ intent
Create an intent with a given action.
Intent(String action, Uri uri)
Create an intent with a given action and for a given data url.
Intent(Context packageContext, Class<?> cls)
Create an intent for a specific component.
Creates an
‘explicit’ intent
Wednesday, March 20, 13 10
11. Implicit Intent
Intent(String action, Uri uri)
The primary pieces of information in an intent are:
• action -- The general action to be performed, such as ACTION_VIEW, ACTION_EDIT,
ACTION_MAIN, etc.
• data -- The data to operate on, such as a person record in the contacts database,
expressed as a Uri.
Wednesday, March 20, 13 11
12. Examples:
• ACTION_VIEW content://contacts/people/1 -- Display information about the person whose identifier is "1".
• ACTION_DIAL content://contacts/people/1 -- Display the phone dialer with the person filled in.
• ACTION_VIEW tel:123 -- Display the phone dialer with the given number filled in. Note how the VIEW action does what
what is considered the most reasonable thing for a particular URI.
• ACTION_DIAL tel:123 -- Display the phone dialer with the given number filled in.
• ACTION_EDIT content://contacts/people/1 -- Edit information about the person whose identifier is "1".
• ACTION_VIEW content://contacts/people/ -- Display a list of people, which the user can browse through. This example is
a typical top-level entry into the Contacts application, showing you the list of people. Selecting a particular person to view
would result in a new intent {ACTION_VIEW content://contacts/N } being used to start an activity to display that person.
http://developer.android.com/reference/android/content/Intent.html
Wednesday, March 20, 13 12
13. Explicit Intent
Intent(Context packageContext, Class<?> cls)
The primary pieces of information in an intent are:
Context -- package context where the class you wish to invoke resides
Class -- name of the class
Wednesday, March 20, 13 13
14. Additional attributes
• category -- Gives additional information about the action to execute.
• type -- Specifies an explicit type (a MIME type) of the intent data.
• component -- Specifies an explicit name of a component class to use for the intent.
• extras -- This is a Bundle of any additional information
Wednesday, March 20, 13 14
15. EasyActivity.java
Example:
Explicit Intent
Activity Launched
Intra-App Context
intent = new Intent(this,
com.chaski.mobilemarchexample.EasyActivity.class);
startActivity(intent);
Class Implementing
Activity
Wednesday, March 20, 13 15
16. Example: Activity launched, now
launch a service!
Explicit Intent
Service Launched
Intra-App
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.easy_layout);
Intent intent = new Intent(this,
com.chaski.mobilemarchexample.EasyService.class);
intent.putExtra("messenger", messenger);
startService(intent);
} messenger
See EasyActivity.java
Wednesday, March 20, 13 16
17. Inside the Service
(EasyService.java)
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Messenger messenger = intent.getParcelableExtra("messenger");
MyRunnable mr = new MyRunnable(messenger);
Thread t = new Thread(mr);
grab messenger
t.start();
return Service.START_STICKY;
}
....
Message message = Message.obtain(null, 1, 0, 0);
try {
Bundle data = new Bundle();
data.putString("mystring", "myvalue:"+i); within myRunnable
message.setData(data);
messenger.send(message);
} catch (RemoteException e) { }
...
Wednesday, March 20, 13 17
18. Activity Handler
packag
public class EasyActivity extends Activity {
MyHandler handler = new MyHandler();
Messenger messenger = new Messenger(handler);
.......
class MyHandler extends Handler {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
String mydata = msg.getData().getString("mystring");
Toast.makeText(getApplicationContext(), "Got Message:"+mydata, Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(getApplicationContext(), "EasyService has ended", Toast.LENGTH_SHORT).show();
default:
super.handleMessage(msg);
}
}
}
}
See EasyActivity.java
Wednesday, March 20, 13 18
19. So far
• 2 Examples
• Launch activity with explicit intent and no
expectation of returned data
• Launch service with explicit intent with
expectation of data passed via messenger/handler
Wednesday, March 20, 13 19
20. Next example
• startActivityForResult - Expect a result from the
calling activity
• new activity registers for broadcast receiver
• new activity starts a service
• service finishes, sends message via broadcast
• Activity finishes and returns result
Wednesday, March 20, 13 20
22. *You can do the same thing with a service
*It takes a couple Extra Steps though
*See simpleActivity.java/simpleService.java
Wednesday, March 20, 13 22
23. @Override
TrivialActivity.java
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.trivial_layout);
receiver = new ResponseReceiver();
registerReceiver(receiver, new
IntentFilter("com.chaski.mobilemarchexample.TrivialActivity.broadcast.update"));
Intent intent = new Intent(this,com.chaski.mobilemarchexample.TrivialService.class);
this.startService(intent);
}
TrivialService will communication
through a BroadcastReceiver
class ResponseReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(getApplicationContext(), "TrivialService has ended",
Toast.LENGTH_SHORT).show();
}
}
Or use a BroadcastReceiver
Wednesday, March 20, 13 23
24. Response via
Broadcast
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
t.start();
return Service.START_STICKY;
}
...
public void SendBroadcast(Boolean result, String Msg) {
Intent i = new Intent();
i.setAction("com.chaski.mobilemarchexample.TrivialActivity.broadcast.update");
i.putExtra("result", result);
i.putExtra("message", Msg);
this.sendBroadcast(i);
}
TrivialService.java
Wednesday, March 20, 13 24
25. Bound and Determined
Bound Service
• The server in a client-server interface.
• Allows components to send requests and receive responses
• Typically does not run in the background indefinitely
Wednesday, March 20, 13 25
26. Bound Services
• A bound service allows other applications to bind to..to interact with it.
• You must implement the onBind()callback
• This method returns an IBinder object that defines the programming
interface that clients can use to interact with the service.
Wednesday, March 20, 13 26
27. Bound Services
• We can use messages as before
• We can invoke functions directly
Wednesday, March 20, 13 27
28. Step 1- Make Service
final Messenger myMessenger = new Messenger(new MessageHandler());
@Override
public IBinder onBind(Intent intent) { Communicating via a messenger
return myMessenger.getBinder();
}
See BoundMessageService.java
public class LocalBoundServiceBinder extends Binder {
LocalBoundService getService() {
return LocalBoundService.this;
}
You }
Communicating via local methods
need a
@Override
public IBinder onBind(Intent intent) {
binder! return binder; See LocalBoundService.java
}
Wednesday, March 20, 13 28
29. Make a connection, Start
the service!
localBoundServiceConnection = new LocalBoundServiceConnection();
intent = new Intent(this,
com.chaski.mobilemarchexample.LocalBoundService.class);
boundServiceBound = bindService(intent, localBoundServiceConnection,
Context.BIND_AUTO_CREATE);
class BoundMessageServiceConnection implements ServiceConnection {
public void onServiceDisconnected(ComponentName name) {
Log.i(TAG, "Service Disconnected");
}
public void onServiceConnected(ComponentName name, IBinder service) {
messageBinder = (IBinder) service;
myMessenger = new Messenger(service);
} BoundActivity.java
};
Wednesday, March 20, 13 29
30. Use the service
localBoundService.getRandomNumber();
BoundActivity.java
/** method for clients */
public int getRandomNumber() {
return mGenerator.nextInt(100);
}
BoundService.java
Wednesday, March 20, 13 30
31. AIDL
• Previous examples work well for services
local to application.
• If you want to expose a service for other
applications, you need an AIDL file.
package com.chaski.mobilemarchexample;
interface AIDLServiceaidl {
Looks just like an interface file! int add(in int value1, in int value2, out
int[] value3);
}
AIDLServiceaidl.aidl
Wednesday, March 20, 13 31
32. class AidlServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder boundService) {
service = AIDLServiceaidl.Stub.asInterface((IBinder) boundService);
Log.i(TAG, "onServiceConnected() connected");
}
public void onServiceDisconnected(ComponentName name) {
service = null;
Log.i(TAG, "onServiceDisconnected() disconnected");
}
}
Connection looks nearly the same
Wednesday, March 20, 13 32
33. AIDL Use is almost the same
int res = 0;
int[] value3 = new int[3];
try {
res = service.add(1, 2, value3);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
See AidlActivity.java
Note: parameters can be used to
pass data back
Wednesday, March 20, 13 33
34. What about implicit
intents, leveraging other
peoples applications
and reducing developer
burden?
Wednesday, March 20, 13 34
35. Lights Camera Action!
Action
intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 987654321);
Request Code
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (requestCode == 987654321) {
Bundle extras = intent.getExtras();
Bitmap bitmap = (Bitmap) extras.get("data");
}
}
Wednesday, March 20, 13 35
36. Implicit via category
intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_APP_EMAIL);
* In this example, we want an application that can
handle email. We don’t care which one.
Wednesday, March 20, 13 36
37. Implicit Intents
• Work from intent filters
• You can define your own
Wednesday, March 20, 13 37
38. Example
Implicit via custom category
intent = new Intent();
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory("jeb");
* category is custom, named jeb!
* Application that handles “jeb” needs this intent-filter
in the manifest
You always need a default
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="jeb"/>
</intent-filter>
Wednesday, March 20, 13 38
39. Example
Implicit Intent via URI
Data
Uri uri = Uri.parse("imdb:///find?q=godfather");
intent =
new Intent(android.content.Intent.ACTION_VIEW, uri);
startActivity(intent);
Action
Wednesday, March 20, 13 39
40. Example
Implicit Intent via Custom URI
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="ted"/>
</intent-filter>
Our Custom URI
Intent sender code:
Uri uri = Uri.parse("ted:");
intent = new Intent(android.content.Intent.ACTION_VIEW, uri);
startActivity(intent);
Wednesday, March 20, 13 40
42. UR’all that… and more!
iOS Inter-App Communication
• Launching apps automatically via URLs
• Providing services from your app
• Sending values and returning results
• Standardizing interfaces with x-callback-url
Wednesday, March 20, 13 42
43. “Launching” Apps
Manually
• “Launching” from user context
• App startup after install, power-up, kill, jettison, crash
• Returning from background
• Spring board (a.k.a Home Screen)
• Tap app icon
• Dock, Folders & Multitasking Bar
• “Search iPhone”
• Siri
• Hold Home button and say app name
Wednesday, March 20, 13 43
44. Launching Apps
Automatically
• URL schemes
• E.g.,http://www.w3schools.com/ fb://friends
• Document/file type support
• Local notifications
• Push notifications
Wednesday, March 20, 13 44
45. Data Sharing
via Network
• Cloud service
• E.g., Facebook, DropBox, proprietary
• Allows non-iOS device and browser access
• iCloud
• Game Center
• Push notifications
Wednesday, March 20, 13 45
46. Data Sharing
on Device
• URL parameters
• E.g.,http://maps.apple.com/?daddr=San+Francisco,
+CA&saddr=cupertino
• Keychain Services
• Document/file type support
• Pasteboards
• Core Audio
• Core MIDI
Wednesday, March 20, 13 46
47. Apple
URL Schemes
Safari http://www.yahoo.com https://www.wellsfargo.com
Mail mailto:frank@wwdcdemo.example.com
Phone tel:1-408-555-5555
Text sms:1-408-555-1212
Maps http://maps.apple.com/?daddr=San+Francisco,
+CA&saddr=cupertino
YouTube http://www.youtube.com/watch?v=2DSrJXQV9Og
iTunes http://phobos.apple.com/WebObjects/MZStore.woa/wa/
viewAlbum?i=156093464&id=156093462&s=143441
Wednesday, March 20, 13 47
48. In-App Services
Native API
Safari UIWebView
Mail MFMailComposeViewController
Phone
Text MFMessageComposeViewController
Map MKMapView
YouTube UIWebView
iTunes
Wednesday, March 20, 13 48
49. Launching App via
HTML Link
• HTML links
<a href="tel:1-408-555-5555">Call your representative</a>
• Safari and Email apps
• UIWebView
Wednesday, March 20, 13 49
50. Link
Auto-Detection
• Auto-detection of link-like text within HTML
• Telephone numbers
• URLs
• Parse-able strings containing “://”
• Missing “http://” prefix
Wednesday, March 20, 13 50
51. Launching app via
Native API
• Objective-C API
UIApplication -canOpenURL:
UIApplication -openURL:
• Example
NSURL *url = [NSURL URLWithString:@"tel:1-408-555-5555"];
if([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
}
Wednesday, March 20, 13 51
52. Custom URL Schemes
• Not cutting edge, but not always well-executed
• Many apps provide a “noun” to launch them
yelp4://
flixter://
angrybirds-free://
angrybirds-hd-free://
• Fewer apps provide “verbs” to control them
yelp:///search?terms=bars&location=sf
Wednesday, March 20, 13 52
53. Custom URL Scheme
Example
googlechrome: Launches Chrome app
Opens new tab and navigates to
googlechrome://www.yahoo.com
http://www.yahoo.com
googlechromes://www.wellsfargo.com Similar to https:
googlechrome-x-callback://x-callback-
url/open?
x-success=myscheme%3A%2F%2F& Specifies display name and
scheme of app for return
x-source=MyApp&
url=http%3A%2F%2Fwww.yahoo.com
Wednesday, March 20, 13 53
56. Scheme “Actions”
• handleOpenURL website
• Search scheme index
skype:thurston.howell.iii?call
skype://lovey?chat
Wednesday, March 20, 13 56
57. Schemes to the Extreme
• akosma software web page
• URL encoding tips
CFURLCreateStringByAddingPercentEscapes()
preferred over
NSString -stringByAddingPercentEscapesUsingEncoding:
• Undocumented(?) Apple URL schemes
• Google Maps, Music,Videos, App Store, iBooks, iBooks Store,
Podcasts
• Safer: comgooglemaps://
• Objective-C code examples
Wednesday, March 20, 13 57
58. “App Launcher” Apps
• Launch Center Pro • Simple Launcher
• Launch+ • Simple Phone Launcher
• Quickpick • Swipemint
• Launcher
• Speed U
• App Gate
Wednesday, March 20, 13 58
59. "App Launcher"
Typical Features
• Pre-canned schemes & • Access to non-scheme
actions iOS features
• Detection of installed apps • Scheduled notifications
• Links to App Store • Organize favorites
• Custom URLs • Icon management
• Clipboard or user prompt • Download new URLs
• In app for iOS features • Uni-directional; no return
Wednesday, March 20, 13 59
60. Your very own
URL scheme
• Choosing a “unique” scheme name
• No official master list beyond IANA
• Priority among conflicts undefined
• Cannot override Apple schemes
• “googlechrome:” instead of “chrome:”
• Search unofficial sources and “advertise”
your own scheme!
Wednesday, March 20, 13 60
64. App Startup
• A.k.a. “launching” vs. returning from background
• Delegate callback API
UIApplicationDelegate -application:didFinishLaunchingWithOptions:
• Example
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSURL *url = [launchOptions
valueForKey:UIApplicationLaunchOptionsURLKey];
NSLog(@"%@", [url absoluteString]);
return YES; // Allow openURL to run
}
Wednesday, March 20, 13 64
65. Smart App Banners
• Displays promotional banner on web page
<meta name="apple-itunes-app" content="app-id=myAppStoreID,
affiliate-data=myAffiliateData, app-argument=myURL">
Offers to take user to App or App Store as appropriate
• E.g., “LinkedIn Connections” email on iPhone
• Tapping button opens Safari “Sign in” page
• If LinkedIn app is installed, banner appears offering
to “OPEN” it
• Tapping OPEN opens app
Wednesday, March 20, 13 65
66. Return to Sender
• Facebook scheme format:
fb<ID>: E.g. , fb165260790249214:
• Google Chrome (as seen earlier)
googlechrome-x-callback://x-callback-url/
• Terminology thesaurus lookup & selection
terminology://x-callback-url/
Wednesday, March 20, 13 66
67. x-callback-url
• Encourages services that perform and return
• Standardizes service API structure
• Format and URL encoding
• Inter-App Communication (IAC)
• Taps & Swipes open source framework
Wednesday, March 20, 13 67
68. How it Works
• App “launch” via URL scheme used for both directions
• Server defines well-known scheme and service
• Client specifies return scheme & delegates
Client Server
Need
It
theserverscheme:...?aclientscheme:...aclienttarget...
Doing
It
aclientscheme:.../aclienttarget?theserverparameters
Got
It
Wednesday, March 20, 13 68
69. Service API Structure
[scheme]://[host]/[action]?[x-callback parameters]&[action parameters]
• host x-callback-url
• x-callback query parameters
• App display name x-source
• Success delegate x-success
• Error delegate x-error
• Cancel delegate x-cancel
Wednesday, March 20, 13 69
70. Terminology App
• Legacy lookup
terminology://heavy
• Modern, but no return requested
terminology://x-callback-url/lookup?text=heavy
Wednesday, March 20, 13 70
71. Terminology
Return Result
• Request return (unencoded)
terminology://x-callback-url/replace?
x-success=myscheme://x-callback-url/myReturnAction&
x-source=MyAppName&
text=heavy
• Return Result
myscheme://x-callback-url/myReturnAction?
text=heavy&
replaceWith=dense&
Wednesday, March 20, 13 71
76. Unauthorized Intent
Reception
• Broadcast Theft
• Eavesdropper can silently read contents
of a broadcast without interrupting
broadcast
• Attacker could launch denial of service
or data injection attack
• Ordered Broadcasts can be subject to
Wednesday, March 20, 13 76
77. Intent Spoofing
• Malicious Broadcast Injection
• Malicious Activity Launch
• Malicious Service Launch
Wednesday, March 20, 13 77
78. How hard is this?
• apktool
• https://code.google.com/p/android-
apktool/
• dare
• http://siis.cse.psu.edu/dare/index.html
Wednesday, March 20, 13 78
79. How hard?
•Get apktool.jar
•https://code.google.com/p/android-apktool/
•Get your apk files
•java -r apktool.jardecode ..
Wednesday, March 20, 13 79
80. Look at that!
Our manifest, our resources.
Oh the humanity!
Text
Wednesday, March 20, 13 80
81. Security
• Don’t mess with peoples data if you don’t have
to.
• When sending private data, use explicit intents
• Internal Intents should always be explicit!
• Strong permissions be used. As strong as
possible.
• Review signature permissions
Wednesday, March 20, 13 81
82. iOS Scheme Security
• URLs inherently insecure
• No HTTPS equivalent
Wednesday, March 20, 13 82
83. Hacking URL schemes
• iOS handling of duplicates
• Masquerading as client
• Masquerading as server
• Misrouting callbacks
• Discovering schemes
• Discovering apps
• Non-App Store hacking tools
Wednesday, March 20, 13 83
84. What can be done?
• Encrypt URL after scheme: (or schemes:// ?)
• Shared secret
• Public key cryptography
• Encrypted data must be “URL parseable” by iOS
and URL encoded
• Send encrypted data out of band
• E.g., iOS Keychain Services
• Shared keychain
Wednesday, March 20, 13 84
85. Keychain Services
• Create Entitlements.plist
• Add keychain-access-group
• ANSI C API
CFDictionaryRef bridged from NSMutableDictionary
OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result)
OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef
*result)
Wednesday, March 20, 13 85
86. I have just one question...
Huh?
Wednesday, March 20, 13 86
87. Thank you!
On the Android banjo and security On the iOS banjo and network
mandolin: protocol fiddle:
Michael Dorin Dan Ratcliff
dorinmike@gmail.com dan_ratcliff@yahoo.com
www.linkedin.com/in/michaeldorin http://www.linkedin.com/in/danratcliff
Wednesday, March 20, 13 87
88. Sources
• Stackoverflow
• http://stackoverflow.com
• Android Developers Guide
• http://developer.android.com/guide
• Intent and Intent Filters, by Sang Shin and Michèle
Garoche
• http://documents.cofares.net/miroires/AndroidPourValeurC/8-android_intent.pdf
• Systems and Internet Infrastructure Security, Dare
• http://siis.cse.psu.edu/dare/installation.html
• Analyzing Inter-Application Communication in Android
• http://www.cs.berkeley.edu/~afelt/intentsecurity-mobisys.pdf
Wednesday, March 20, 13 88
89. Sources
• Apple URL Scheme Reference
• http://developer.apple.com/library/ios/#featuredarticles/
iPhoneURLScheme_Reference/Introduction/Introduction.html%23//apple_ref/doc/uid/
TP40007891-SW1
• Communicating with Other Apps
• http://developer.apple.com/library/ios/#documentation/iphone/conceptual/
iphoneosprogrammingguide/AdvancedAppTricks/AdvancedAppTricks.html
• iPhone Apps | Yelp for Developers
• http://www.yelp.com/developers/documentation/iphone
• Opening Links in Chrome for iOS
• https://developers.google.com/chrome/mobile/docs/ios-links
Wednesday, March 20, 13 89
90. Sources
• iHasApp - Installed App Detection
• http://www.ihasapp.com
• handleOpenURL: Shared App Communication on iOS
• http://handleopenurl.com
• Skype URI Handler
• http://dev.skype.com/desktop-api-reference#URI
• IPhone URL Schemes - akosma wiki
• http://wiki.akosma.com/IPhone_URL_Schemes
• Google's New iOS Maps App and URL Scheme
• http://www.pureoxygenmobile.com/googles-new-maps-ios-app-and-url-scheme/
Wednesday, March 20, 13 90
91. Sources
• Launch Center Pro
• https://itunes.apple.com/us/app/launch-center-pro/id532016360?mt=8
• Launch+
• https://itunes.apple.com/us/app/launch+/id500606931?mt=8
• Quickpick
• http://www.neoos.ch/https://itunes.apple.com/us/app/id483079724/quickpick
• Launcher
• https://itunes.apple.com/us/app/launcher-quick-actions-shortcuts!/id511645204?
mt=8
• Speed U
• https://itunes.apple.com/us/app/speed-u/id510914771?mt=8
Wednesday, March 20, 13 91