@thathoff/cordova-plugin-universal-links 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/LICENSE +22 -0
  3. package/README.md +908 -0
  4. package/docs/images/app-associated-domains.jpg +0 -0
  5. package/docs/images/app-id-team-prefix.jpg +0 -0
  6. package/docs/images/app-id.jpg +0 -0
  7. package/docs/images/branch-io-link-domain.jpg +0 -0
  8. package/docs/images/branch-io.jpg +0 -0
  9. package/docs/images/developer-console.jpg +0 -0
  10. package/hooks/afterPrepareHook.js +86 -0
  11. package/hooks/beforePluginInstallHook.js +55 -0
  12. package/hooks/iosBeforePrepareHook.js +74 -0
  13. package/hooks/lib/android/manifestWriter.js +320 -0
  14. package/hooks/lib/android/webSiteHook.js +162 -0
  15. package/hooks/lib/configXmlHelper.js +117 -0
  16. package/hooks/lib/configXmlParser.js +145 -0
  17. package/hooks/lib/ios/appleAppSiteAssociationFile.js +173 -0
  18. package/hooks/lib/ios/projectEntitlements.js +174 -0
  19. package/hooks/lib/ios/xcodePreferences.js +243 -0
  20. package/hooks/lib/xmlHelper.js +57 -0
  21. package/package.json +58 -0
  22. package/plugin.xml +106 -0
  23. package/src/android/com/nordnetab/cordova/ul/UniversalLinksPlugin.java +221 -0
  24. package/src/android/com/nordnetab/cordova/ul/js/JSAction.java +19 -0
  25. package/src/android/com/nordnetab/cordova/ul/model/JSMessage.java +193 -0
  26. package/src/android/com/nordnetab/cordova/ul/model/ULHost.java +85 -0
  27. package/src/android/com/nordnetab/cordova/ul/model/ULPath.java +43 -0
  28. package/src/android/com/nordnetab/cordova/ul/parser/ULConfigXmlParser.java +156 -0
  29. package/src/android/com/nordnetab/cordova/ul/parser/XmlTags.java +49 -0
  30. package/src/ios/AppDelegate+CULPlugin.h +17 -0
  31. package/src/ios/AppDelegate+CULPlugin.m +32 -0
  32. package/src/ios/CULPlugin.h +38 -0
  33. package/src/ios/CULPlugin.m +176 -0
  34. package/src/ios/JS/CDVInvokedUrlCommand+CULPlugin.h +21 -0
  35. package/src/ios/JS/CDVInvokedUrlCommand+CULPlugin.m +19 -0
  36. package/src/ios/JS/CDVPluginResult+CULPlugin.h +29 -0
  37. package/src/ios/JS/CDVPluginResult+CULPlugin.m +157 -0
  38. package/src/ios/Model/CULHost.h +63 -0
  39. package/src/ios/Model/CULHost.m +50 -0
  40. package/src/ios/Model/CULPath.h +36 -0
  41. package/src/ios/Model/CULPath.m +21 -0
  42. package/src/ios/Parser/JSON/CULConfigJsonParser.h +22 -0
  43. package/src/ios/Parser/JSON/CULConfigJsonParser.m +60 -0
  44. package/src/ios/Parser/XML/CULConfigXmlParser.h +22 -0
  45. package/src/ios/Parser/XML/CULConfigXmlParser.m +123 -0
  46. package/src/ios/Parser/XML/CULXmlTags.h +54 -0
  47. package/src/ios/Parser/XML/CULXmlTags.m +22 -0
  48. package/src/ios/Utils/NSBundle+CULPlugin.h +22 -0
  49. package/src/ios/Utils/NSBundle+CULPlugin.m +15 -0
  50. package/ul_web_hooks/android_web_hook_tpl.html +23 -0
  51. package/www/universal_links.js +56 -0
@@ -0,0 +1,221 @@
1
+ package com.nordnetab.cordova.ul;
2
+
3
+ import android.content.Intent;
4
+ import android.net.Uri;
5
+ import android.text.TextUtils;
6
+ import android.util.Log;
7
+
8
+ import com.nordnetab.cordova.ul.js.JSAction;
9
+ import com.nordnetab.cordova.ul.model.JSMessage;
10
+ import com.nordnetab.cordova.ul.model.ULHost;
11
+ import com.nordnetab.cordova.ul.parser.ULConfigXmlParser;
12
+
13
+ import org.apache.cordova.CallbackContext;
14
+ import org.apache.cordova.CordovaArgs;
15
+ import org.apache.cordova.CordovaInterface;
16
+ import org.apache.cordova.CordovaPlugin;
17
+ import org.apache.cordova.CordovaWebView;
18
+ import org.apache.cordova.PluginResult;
19
+ import org.json.JSONException;
20
+
21
+ import java.util.HashMap;
22
+ import java.util.List;
23
+ import java.util.Map;
24
+ import java.util.Set;
25
+
26
+ /**
27
+ * Created by Nikolay Demyankov on 09.09.15.
28
+ * <p/>
29
+ * Plugin main class.
30
+ * Communicates with the JS side, handles launch intents and so on.
31
+ */
32
+ public class UniversalLinksPlugin extends CordovaPlugin {
33
+
34
+ // list of hosts, defined in config.xml
35
+ private List<ULHost> supportedHosts;
36
+
37
+ // list of subscribers
38
+ private Map<String, CallbackContext> subscribers;
39
+
40
+ // stored message, that is captured on application launch
41
+ private JSMessage storedMessage;
42
+
43
+ // region Public API
44
+
45
+ @Override
46
+ public void initialize(CordovaInterface cordova, CordovaWebView webView) {
47
+ super.initialize(cordova, webView);
48
+
49
+ supportedHosts = new ULConfigXmlParser(cordova.getActivity()).parse();
50
+
51
+ if (subscribers == null) {
52
+ subscribers = new HashMap<String, CallbackContext>();
53
+ }
54
+
55
+ handleIntent(cordova.getActivity().getIntent());
56
+ }
57
+
58
+ @Override
59
+ public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
60
+ boolean isHandled = true;
61
+ if (JSAction.SUBSCRIBE.equals(action)) {
62
+ subscribeForEvent(args, callbackContext);
63
+ } else if (JSAction.UNSUBSCRIBE.equals(action)) {
64
+ unsubscribeFromEvent(args);
65
+ } else {
66
+ isHandled = false;
67
+ }
68
+
69
+ return isHandled;
70
+ }
71
+
72
+ @Override
73
+ public void onNewIntent(Intent intent) {
74
+ handleIntent(intent);
75
+ }
76
+
77
+ // endregion
78
+
79
+ // region JavaScript methods
80
+
81
+ /**
82
+ * Add subscriber for the event.
83
+ *
84
+ * @param arguments arguments, passed from JS side
85
+ * @param callbackContext callback to use when event is captured
86
+ */
87
+ private void subscribeForEvent(final CordovaArgs arguments, final CallbackContext callbackContext) {
88
+ final String eventName = getEventNameFromArguments(arguments);
89
+ if (TextUtils.isEmpty(eventName)) {
90
+ return;
91
+ }
92
+
93
+ subscribers.put(eventName, callbackContext);
94
+ tryToConsumeEvent();
95
+ }
96
+
97
+ /**
98
+ * Remove subscriber from the event.
99
+ *
100
+ * @param arguments arguments, passed from JS side
101
+ */
102
+ private void unsubscribeFromEvent(final CordovaArgs arguments) {
103
+ if (subscribers.size() == 0) {
104
+ return;
105
+ }
106
+
107
+ final String eventName = getEventNameFromArguments(arguments);
108
+ if (TextUtils.isEmpty(eventName)) {
109
+ return;
110
+ }
111
+
112
+ subscribers.remove(eventName);
113
+ }
114
+
115
+ /**
116
+ * Get event name from the cordova arguments.
117
+ *
118
+ * @param arguments received arguments
119
+ * @return event name; <code>null</code> if non is found
120
+ */
121
+ private String getEventNameFromArguments(final CordovaArgs arguments) {
122
+ String eventName = null;
123
+ try {
124
+ eventName = arguments.getString(0);
125
+ } catch (JSONException e) {
126
+ Log.d("UniversalLinks", "Failed to get event name from the JS arguments", e);
127
+ }
128
+
129
+ return eventName;
130
+ }
131
+
132
+ /**
133
+ * Try to send event to the subscribers.
134
+ */
135
+ private void tryToConsumeEvent() {
136
+ if (subscribers.size() == 0 || storedMessage == null) {
137
+ return;
138
+ }
139
+
140
+ final String storedEventName = storedMessage.getEventName();
141
+ final Set<Map.Entry<String, CallbackContext>> subscribersSet = subscribers.entrySet();
142
+ for (Map.Entry<String, CallbackContext> subscriber : subscribersSet) {
143
+ final String eventName = subscriber.getKey();
144
+ if (eventName.equals(storedEventName)) {
145
+ sendMessageToJs(storedMessage, subscriber.getValue());
146
+ storedMessage = null;
147
+ break;
148
+ }
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Send message to JS side.
154
+ *
155
+ * @param message message to send
156
+ * @param callback to what callback we are sending the message
157
+ */
158
+ private void sendMessageToJs(JSMessage message, CallbackContext callback) {
159
+ final PluginResult result = new PluginResult(PluginResult.Status.OK, message);
160
+ result.setKeepCallback(true);
161
+ callback.sendPluginResult(result);
162
+ }
163
+
164
+ // endregion
165
+
166
+ // region Intent handling
167
+
168
+ /**
169
+ * Handle launch intent.
170
+ * If it is an UL intent - then event will be dispatched to the JS side.
171
+ *
172
+ * @param intent launch intent
173
+ */
174
+ private void handleIntent(Intent intent) {
175
+ if (intent == null || supportedHosts == null || supportedHosts.size() == 0) {
176
+ return;
177
+ }
178
+
179
+ // read intent
180
+ String action = intent.getAction();
181
+ Uri launchUri = intent.getData();
182
+
183
+ // if app was not launched by the url - ignore
184
+ if (!Intent.ACTION_VIEW.equals(action) || launchUri == null) {
185
+ return;
186
+ }
187
+
188
+ // try to find host in the hosts list from the config.xml
189
+ ULHost host = findHostByUrl(launchUri);
190
+ if (host == null) {
191
+ Log.d("UniversalLinks", "Host " + launchUri.getHost() + " is not supported");
192
+ return;
193
+ }
194
+
195
+ // store message and try to consume it
196
+ storedMessage = new JSMessage(host, launchUri);
197
+ tryToConsumeEvent();
198
+ }
199
+
200
+ /**
201
+ * Find host entry that matches the launch url.
202
+ *
203
+ * @param url launch url
204
+ * @return host entry; <code>null</code> - if none were found
205
+ */
206
+ private ULHost findHostByUrl(Uri url) {
207
+ ULHost host = null;
208
+ final String launchHost = url.getHost().toLowerCase();
209
+ for (ULHost supportedHost : supportedHosts) {
210
+ if (supportedHost.getName().equals(launchHost) ||
211
+ supportedHost.getName().startsWith("*.") && launchHost.endsWith(supportedHost.getName().substring(1))) {
212
+ host = supportedHost;
213
+ break;
214
+ }
215
+ }
216
+
217
+ return host;
218
+ }
219
+
220
+ // endregion
221
+ }
@@ -0,0 +1,19 @@
1
+ package com.nordnetab.cordova.ul.js;
2
+
3
+ /**
4
+ * Created by Nikolay Demyankov on 09.09.15.
5
+ * <p/>
6
+ * Class holds list of method names that is called from JS side.
7
+ */
8
+ public final class JSAction {
9
+
10
+ /**
11
+ * Subscribe to event.
12
+ */
13
+ public static final String SUBSCRIBE = "jsSubscribeForEvent";
14
+
15
+ /**
16
+ * Unsubscribe from event.
17
+ */
18
+ public static final String UNSUBSCRIBE = "jsUnsubscribeFromEvent";
19
+ }
@@ -0,0 +1,193 @@
1
+ package com.nordnetab.cordova.ul.model;
2
+
3
+ import android.net.Uri;
4
+ import android.util.Log;
5
+
6
+ import org.json.JSONException;
7
+ import org.json.JSONObject;
8
+
9
+ import java.util.List;
10
+ import java.util.Set;
11
+
12
+ /**
13
+ * Created by Nikolay Demyankov on 10.09.15.
14
+ * <p/>
15
+ * Model for the message entry, that is send to JS.
16
+ */
17
+ public class JSMessage extends JSONObject {
18
+
19
+ // keys for the message base structure
20
+ private static final class JSGeneralKeys {
21
+ /**
22
+ * Event name
23
+ */
24
+ public static final String EVENT = "event";
25
+
26
+ /**
27
+ * Message data block
28
+ */
29
+ public static final String DATA = "data";
30
+ }
31
+
32
+ // keys for the message data block
33
+ private static final class JSDataKeys {
34
+
35
+ /**
36
+ * Path part of the url
37
+ */
38
+ public static final String PATH = "path";
39
+
40
+ /**
41
+ * Scheme of the url
42
+ */
43
+ public static final String SCHEME = "scheme";
44
+
45
+ /**
46
+ * Host of the url
47
+ */
48
+ public static final String HOST = "host";
49
+
50
+ /**
51
+ * Hash (fragment) from the url - data after '#'
52
+ */
53
+ public static final String HASH = "hash";
54
+
55
+ /**
56
+ * Query parameters - data after '?'
57
+ */
58
+ public static final String PARAMS = "params";
59
+
60
+ /**
61
+ * Launch url as it is
62
+ */
63
+ public static final String ORIGIN = "url";
64
+ }
65
+
66
+ private String eventName;
67
+
68
+ /**
69
+ * Constructor
70
+ *
71
+ * @param host host entry that corresponds to the launching url
72
+ * @param originalUri launch url
73
+ */
74
+ public JSMessage(ULHost host, Uri originalUri) {
75
+ setEventName(host, originalUri);
76
+ setMessageData(host, originalUri);
77
+ }
78
+
79
+ /**
80
+ * Getter for event name of this message.
81
+ *
82
+ * @return event name
83
+ */
84
+ public String getEventName() {
85
+ return eventName;
86
+ }
87
+
88
+ // region Event name setters
89
+
90
+ /**
91
+ * Set event name for this message entry.
92
+ */
93
+ private void setEventName(ULHost host, Uri originalUri) {
94
+ eventName = getEventName(host, originalUri);
95
+
96
+ try {
97
+ put(JSGeneralKeys.EVENT, eventName);
98
+ } catch (JSONException e) {
99
+ Log.d("UniversalLinks", "Failed to set event name", e);
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Find event name based on the launching url.
105
+ * By default, event name from the host object will be used.
106
+ * But if we have some path entry in the host and it matches the one from the launch url - his event name will be used.
107
+ */
108
+ private String getEventName(ULHost host, Uri originalUri) {
109
+ String event = host.getEvent();
110
+ final String originPath = originalUri.getPath().toLowerCase();
111
+ final List<ULPath> hostPathsList = host.getPaths();
112
+ for (ULPath hostPath : hostPathsList) {
113
+ final String hostPathUrl = hostPath.getUrl();
114
+ if (hostPathUrl == null) {
115
+ continue;
116
+ }
117
+
118
+ if (originPath.matches(hostPathUrl)) {
119
+ event = hostPath.getEvent();
120
+ break;
121
+ }
122
+ }
123
+
124
+ return event;
125
+ }
126
+
127
+ // endregion
128
+
129
+ // region Data block setters
130
+
131
+ /**
132
+ * Fill data block with corresponding information.
133
+ */
134
+ private void setMessageData(ULHost host, Uri originalUri) {
135
+ final JSONObject dataObject = new JSONObject();
136
+
137
+ try {
138
+ setOriginalUrl(dataObject, originalUri);
139
+ setHostData(dataObject, host);
140
+ setPathData(dataObject, originalUri);
141
+
142
+ put(JSGeneralKeys.DATA, dataObject);
143
+ } catch (JSONException e) {
144
+ Log.d("UniversalLinks", "Failed to set event data", e);
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Put launch url to the data block
150
+ */
151
+ private void setOriginalUrl(JSONObject dataObject, Uri originalUri) throws JSONException {
152
+ dataObject.put(JSDataKeys.ORIGIN, originalUri.toString());
153
+ }
154
+
155
+ /**
156
+ * Put host name and scheme into data block
157
+ */
158
+ private void setHostData(JSONObject dataObject, ULHost host) throws JSONException {
159
+ dataObject.put(JSDataKeys.HOST, host.getName());
160
+ dataObject.put(JSDataKeys.SCHEME, host.getScheme());
161
+ }
162
+
163
+ /**
164
+ * Put path information into data block
165
+ */
166
+ private void setPathData(JSONObject dataObject, Uri originalUri) throws JSONException {
167
+ dataObject.put(JSDataKeys.HASH, originalUri.getFragment());
168
+ dataObject.put(JSDataKeys.PATH, originalUri.getPath());
169
+
170
+ final JSONObject queryParams = getQueryParamsFromUri(originalUri);
171
+ dataObject.put(JSDataKeys.PARAMS, queryParams);
172
+ }
173
+
174
+ /**
175
+ * Parse query params.
176
+ * For example, if we have link like so: http://somedomain.com/some/path?foo=fooVal&bar=barVal , then
177
+ * resulting object will be {foo: fooVal, bar: barVal}.
178
+ *
179
+ * @return json object
180
+ */
181
+ private JSONObject getQueryParamsFromUri(Uri originalUri) throws JSONException, UnsupportedOperationException {
182
+ JSONObject queryParams = new JSONObject();
183
+ Set<String> keysList = originalUri.getQueryParameterNames();
184
+ for (String key : keysList) {
185
+ final String value = originalUri.getQueryParameter(key);
186
+ queryParams.put(key, value);
187
+ }
188
+
189
+ return queryParams;
190
+ }
191
+
192
+ // endregion
193
+ }
@@ -0,0 +1,85 @@
1
+ package com.nordnetab.cordova.ul.model;
2
+
3
+ import java.util.ArrayList;
4
+ import java.util.List;
5
+
6
+ /**
7
+ * Created by Nikolay Demyankov on 09.09.15.
8
+ * <p/>
9
+ * Model for <host /> entry, specified in config.xml.
10
+ */
11
+ public class ULHost {
12
+
13
+ // default event name, that is dispatched to JS if none was set to the host or path
14
+ private static final String DEFAULT_EVENT = "didLaunchAppFromLink";
15
+
16
+ // default scheme for the host
17
+ private static final String DEFAULT_SCHEME = "http";
18
+
19
+ private final List<ULPath> paths;
20
+ private final String name;
21
+ private final String scheme;
22
+ private String event;
23
+
24
+ /**
25
+ * Constructor
26
+ *
27
+ * @param name host name
28
+ * @param scheme host scheme
29
+ * @param event event that corresponds to this host
30
+ */
31
+ public ULHost(final String name, final String scheme, final String event) {
32
+ this.name = name.toLowerCase();
33
+ this.scheme = (scheme == null) ? DEFAULT_SCHEME : scheme;
34
+ this.event = (event == null) ? DEFAULT_EVENT : event;
35
+ this.paths = new ArrayList<ULPath>();
36
+ }
37
+
38
+ /**
39
+ * Getter for the event name that is sent to JS when user clicks on the link from this host.
40
+ * Defined as 'event' attribute.
41
+ *
42
+ * @return event name
43
+ */
44
+ public String getEvent() {
45
+ return event;
46
+ }
47
+
48
+ /**
49
+ * Setter for event name.
50
+ *
51
+ * @param event event name
52
+ */
53
+ public void setEvent(final String event) {
54
+ this.event = event;
55
+ }
56
+
57
+ /**
58
+ * Getter for the list of paths, that is set for that host in config.xml.
59
+ *
60
+ * @return list of hosts
61
+ */
62
+ public List<ULPath> getPaths() {
63
+ return paths;
64
+ }
65
+
66
+ /**
67
+ * Getter for the host name.
68
+ * Defined as 'name' attribute.
69
+ *
70
+ * @return host name
71
+ */
72
+ public String getName() {
73
+ return name;
74
+ }
75
+
76
+ /**
77
+ * Getter for host scheme.
78
+ * Defined as 'scheme' attribute.
79
+ *
80
+ * @return scheme
81
+ */
82
+ public String getScheme() {
83
+ return scheme;
84
+ }
85
+ }
@@ -0,0 +1,43 @@
1
+ package com.nordnetab.cordova.ul.model;
2
+
3
+ /**
4
+ * Created by Nikolay Demyankov on 09.09.15.
5
+ * <p/>
6
+ * Model for <path /> entry for host in config.xml
7
+ */
8
+ public class ULPath {
9
+
10
+ private final String url;
11
+ private final String event;
12
+
13
+ /**
14
+ * Constructor
15
+ *
16
+ * @param url path url
17
+ * @param event event name
18
+ */
19
+ public ULPath(final String url, final String event) {
20
+ this.url = url.replace("*", "(.*)").toLowerCase();
21
+ this.event = event;
22
+ }
23
+
24
+ /**
25
+ * Getter for path url.
26
+ * Defined as 'url' attribute.
27
+ *
28
+ * @return path url
29
+ */
30
+ public String getUrl() {
31
+ return url;
32
+ }
33
+
34
+ /**
35
+ * Getter for the event name that is dispatched when application is launched from the link with this path.
36
+ * Defined as 'event' attribute.
37
+ *
38
+ * @return event name
39
+ */
40
+ public String getEvent() {
41
+ return event;
42
+ }
43
+ }