@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.
- package/CHANGELOG.md +84 -0
- package/LICENSE +22 -0
- package/README.md +908 -0
- package/docs/images/app-associated-domains.jpg +0 -0
- package/docs/images/app-id-team-prefix.jpg +0 -0
- package/docs/images/app-id.jpg +0 -0
- package/docs/images/branch-io-link-domain.jpg +0 -0
- package/docs/images/branch-io.jpg +0 -0
- package/docs/images/developer-console.jpg +0 -0
- package/hooks/afterPrepareHook.js +86 -0
- package/hooks/beforePluginInstallHook.js +55 -0
- package/hooks/iosBeforePrepareHook.js +74 -0
- package/hooks/lib/android/manifestWriter.js +320 -0
- package/hooks/lib/android/webSiteHook.js +162 -0
- package/hooks/lib/configXmlHelper.js +117 -0
- package/hooks/lib/configXmlParser.js +145 -0
- package/hooks/lib/ios/appleAppSiteAssociationFile.js +173 -0
- package/hooks/lib/ios/projectEntitlements.js +174 -0
- package/hooks/lib/ios/xcodePreferences.js +243 -0
- package/hooks/lib/xmlHelper.js +57 -0
- package/package.json +58 -0
- package/plugin.xml +106 -0
- package/src/android/com/nordnetab/cordova/ul/UniversalLinksPlugin.java +221 -0
- package/src/android/com/nordnetab/cordova/ul/js/JSAction.java +19 -0
- package/src/android/com/nordnetab/cordova/ul/model/JSMessage.java +193 -0
- package/src/android/com/nordnetab/cordova/ul/model/ULHost.java +85 -0
- package/src/android/com/nordnetab/cordova/ul/model/ULPath.java +43 -0
- package/src/android/com/nordnetab/cordova/ul/parser/ULConfigXmlParser.java +156 -0
- package/src/android/com/nordnetab/cordova/ul/parser/XmlTags.java +49 -0
- package/src/ios/AppDelegate+CULPlugin.h +17 -0
- package/src/ios/AppDelegate+CULPlugin.m +32 -0
- package/src/ios/CULPlugin.h +38 -0
- package/src/ios/CULPlugin.m +176 -0
- package/src/ios/JS/CDVInvokedUrlCommand+CULPlugin.h +21 -0
- package/src/ios/JS/CDVInvokedUrlCommand+CULPlugin.m +19 -0
- package/src/ios/JS/CDVPluginResult+CULPlugin.h +29 -0
- package/src/ios/JS/CDVPluginResult+CULPlugin.m +157 -0
- package/src/ios/Model/CULHost.h +63 -0
- package/src/ios/Model/CULHost.m +50 -0
- package/src/ios/Model/CULPath.h +36 -0
- package/src/ios/Model/CULPath.m +21 -0
- package/src/ios/Parser/JSON/CULConfigJsonParser.h +22 -0
- package/src/ios/Parser/JSON/CULConfigJsonParser.m +60 -0
- package/src/ios/Parser/XML/CULConfigXmlParser.h +22 -0
- package/src/ios/Parser/XML/CULConfigXmlParser.m +123 -0
- package/src/ios/Parser/XML/CULXmlTags.h +54 -0
- package/src/ios/Parser/XML/CULXmlTags.m +22 -0
- package/src/ios/Utils/NSBundle+CULPlugin.h +22 -0
- package/src/ios/Utils/NSBundle+CULPlugin.m +15 -0
- package/ul_web_hooks/android_web_hook_tpl.html +23 -0
- package/www/universal_links.js +56 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
package com.nordnetab.cordova.ul.parser;
|
|
2
|
+
|
|
3
|
+
import android.content.Context;
|
|
4
|
+
import android.text.TextUtils;
|
|
5
|
+
|
|
6
|
+
import com.nordnetab.cordova.ul.model.ULHost;
|
|
7
|
+
import com.nordnetab.cordova.ul.model.ULPath;
|
|
8
|
+
|
|
9
|
+
import org.apache.cordova.ConfigXmlParser;
|
|
10
|
+
import org.xmlpull.v1.XmlPullParser;
|
|
11
|
+
|
|
12
|
+
import java.util.ArrayList;
|
|
13
|
+
import java.util.List;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Created by Nikolay Demyankov on 09.09.15.
|
|
17
|
+
* <p/>
|
|
18
|
+
* Parser for config.xml. Reads only plugin-specific preferences.
|
|
19
|
+
*/
|
|
20
|
+
public class ULConfigXmlParser extends ConfigXmlParser {
|
|
21
|
+
|
|
22
|
+
private final Context context;
|
|
23
|
+
private List<ULHost> hostsList;
|
|
24
|
+
|
|
25
|
+
private boolean isInsideMainTag;
|
|
26
|
+
private boolean didParseMainBlock;
|
|
27
|
+
private boolean isInsideHostBlock;
|
|
28
|
+
private ULHost processedHost;
|
|
29
|
+
|
|
30
|
+
// region Public API
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Constructor
|
|
34
|
+
*
|
|
35
|
+
* @param context application context
|
|
36
|
+
*/
|
|
37
|
+
public ULConfigXmlParser(Context context) {
|
|
38
|
+
this.context = context;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Parse config.xml
|
|
43
|
+
*
|
|
44
|
+
* @return list of hosts, defined in the config file
|
|
45
|
+
*/
|
|
46
|
+
public List<ULHost> parse() {
|
|
47
|
+
resetValuesToDefaultState();
|
|
48
|
+
super.parse(context);
|
|
49
|
+
|
|
50
|
+
return hostsList;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// endregion
|
|
54
|
+
|
|
55
|
+
// region XML processing
|
|
56
|
+
|
|
57
|
+
@Override
|
|
58
|
+
public void handleStartTag(XmlPullParser xml) {
|
|
59
|
+
if (didParseMainBlock) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
final String name = xml.getName();
|
|
64
|
+
if (!isInsideMainTag && XmlTags.MAIN_TAG.equals(name)) {
|
|
65
|
+
isInsideMainTag = true;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!isInsideMainTag) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (!isInsideHostBlock && XmlTags.HOST_TAG.equals(name)) {
|
|
74
|
+
isInsideHostBlock = true;
|
|
75
|
+
processHostBlock(xml);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (isInsideHostBlock && XmlTags.PATH_TAG.equals(name)) {
|
|
80
|
+
processPathBlock(xml);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
@Override
|
|
85
|
+
public void handleEndTag(XmlPullParser xml) {
|
|
86
|
+
if (didParseMainBlock) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
final String name = xml.getName();
|
|
91
|
+
|
|
92
|
+
if (isInsideHostBlock && XmlTags.HOST_TAG.equals(name)) {
|
|
93
|
+
isInsideHostBlock = false;
|
|
94
|
+
hostsList.add(processedHost);
|
|
95
|
+
processedHost = null;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (XmlTags.MAIN_TAG.equals(name)) {
|
|
100
|
+
isInsideMainTag = false;
|
|
101
|
+
didParseMainBlock = true;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Parse <host />
|
|
107
|
+
*/
|
|
108
|
+
private void processHostBlock(XmlPullParser xml) {
|
|
109
|
+
final String hostName = xml.getAttributeValue(null, XmlTags.HOST_NAME_ATTRIBUTE);
|
|
110
|
+
final String eventName = xml.getAttributeValue(null, XmlTags.HOST_EVENT_ATTRIBUTE);
|
|
111
|
+
final String scheme = xml.getAttributeValue(null, XmlTags.HOST_SCHEME_ATTRIBUTE);
|
|
112
|
+
|
|
113
|
+
processedHost = new ULHost(hostName, scheme, eventName);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Parse <path />
|
|
118
|
+
*/
|
|
119
|
+
private void processPathBlock(XmlPullParser xml) {
|
|
120
|
+
final String url = xml.getAttributeValue(null, XmlTags.PATH_URL_TAG);
|
|
121
|
+
String event = xml.getAttributeValue(null, XmlTags.PATH_EVENT_TAG);
|
|
122
|
+
|
|
123
|
+
// skip wildcard urls
|
|
124
|
+
if ("*".equals(url) || ".*".equals(url)) {
|
|
125
|
+
// but if path has event name - set it to host
|
|
126
|
+
if (!TextUtils.isEmpty(event)) {
|
|
127
|
+
processedHost.setEvent(event);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// if event name is empty - use one from the host
|
|
134
|
+
if (TextUtils.isEmpty(event)) {
|
|
135
|
+
event = processedHost.getEvent();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// create path entry
|
|
139
|
+
ULPath path = new ULPath(url, event);
|
|
140
|
+
processedHost.getPaths().add(path);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// endregion
|
|
144
|
+
|
|
145
|
+
// region Private API
|
|
146
|
+
|
|
147
|
+
private void resetValuesToDefaultState() {
|
|
148
|
+
hostsList = new ArrayList<ULHost>();
|
|
149
|
+
isInsideMainTag = false;
|
|
150
|
+
didParseMainBlock = false;
|
|
151
|
+
isInsideHostBlock = false;
|
|
152
|
+
processedHost = null;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// endregion
|
|
156
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
package com.nordnetab.cordova.ul.parser;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Created by Nikolay Demyankov on 10.09.15.
|
|
5
|
+
* <p/>
|
|
6
|
+
* XML tags that is used in config.xml to specify plugin preferences.
|
|
7
|
+
*/
|
|
8
|
+
final class XmlTags {
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Main tag in which we define plugin related stuff
|
|
12
|
+
*/
|
|
13
|
+
public static final String MAIN_TAG = "universal-links";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Host main tag
|
|
17
|
+
*/
|
|
18
|
+
public static final String HOST_TAG = "host";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Scheme attribute for the host entry
|
|
22
|
+
*/
|
|
23
|
+
public static final String HOST_SCHEME_ATTRIBUTE = "scheme";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Name attribute for the host entry
|
|
27
|
+
*/
|
|
28
|
+
public static final String HOST_NAME_ATTRIBUTE = "name";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Event attribute for the host entry
|
|
32
|
+
*/
|
|
33
|
+
public static final String HOST_EVENT_ATTRIBUTE = "event";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Path main tag
|
|
37
|
+
*/
|
|
38
|
+
public static final String PATH_TAG = "path";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Url attribute for the path entry
|
|
42
|
+
*/
|
|
43
|
+
public static final String PATH_URL_TAG = "url";
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Event attribute for the path entry
|
|
47
|
+
*/
|
|
48
|
+
public static final String PATH_EVENT_TAG = "event";
|
|
49
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AppDelegate+CULPlugin.h
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 15.09.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import "AppDelegate.h"
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Category for the AppDelegate that overrides application:continueUserActivity:restorationHandler method,
|
|
11
|
+
* so we could handle application launch when user clicks on the link in the browser.
|
|
12
|
+
*/
|
|
13
|
+
@interface AppDelegate (CULPlugin)
|
|
14
|
+
|
|
15
|
+
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler;
|
|
16
|
+
|
|
17
|
+
@end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//
|
|
2
|
+
// AppDelegate+CULPlugin.m
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 15.09.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import "AppDelegate+CULPlugin.h"
|
|
8
|
+
#import "CULPlugin.h"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Plugin name in config.xml
|
|
12
|
+
*/
|
|
13
|
+
static NSString *const PLUGIN_NAME = @"UniversalLinks";
|
|
14
|
+
|
|
15
|
+
@implementation AppDelegate (CULPlugin)
|
|
16
|
+
|
|
17
|
+
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *))restorationHandler {
|
|
18
|
+
// ignore activities that are not for Universal Links
|
|
19
|
+
if (![userActivity.activityType isEqualToString:NSUserActivityTypeBrowsingWeb] || userActivity.webpageURL == nil) {
|
|
20
|
+
return NO;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// get instance of the plugin and let it handle the userActivity object
|
|
24
|
+
CULPlugin *plugin = [self.viewController getCommandInstance:PLUGIN_NAME];
|
|
25
|
+
if (plugin == nil) {
|
|
26
|
+
return NO;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return [plugin handleUserActivity:userActivity];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CULPlugin.h
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 14.09.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import <Foundation/Foundation.h>
|
|
8
|
+
#import <Cordova/CDVPlugin.h>
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Plugin main class.
|
|
12
|
+
*/
|
|
13
|
+
@interface CULPlugin : CDVPlugin
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Subscribe to event.
|
|
17
|
+
*
|
|
18
|
+
* @param command command from js side with event name and callback id.
|
|
19
|
+
*/
|
|
20
|
+
- (void)jsSubscribeForEvent:(CDVInvokedUrlCommand *)command;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Unsubscribe from event.
|
|
24
|
+
*
|
|
25
|
+
* @param command command from js side with event name
|
|
26
|
+
*/
|
|
27
|
+
- (void)jsUnsubscribeFromEvent:(CDVInvokedUrlCommand *)command;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Try to hanlde application launch when user clicked on the link.
|
|
31
|
+
*
|
|
32
|
+
* @param userActivity object with information about the application launch
|
|
33
|
+
*
|
|
34
|
+
* @return <code>true</code> - if this is a universal link and it is defined in config.xml; otherwise - <code>false</code>
|
|
35
|
+
*/
|
|
36
|
+
- (BOOL)handleUserActivity:(NSUserActivity *)userActivity;
|
|
37
|
+
|
|
38
|
+
@end
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CULPlugin.m
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 14.09.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import "CULPlugin.h"
|
|
8
|
+
#import "CULConfigXmlParser.h"
|
|
9
|
+
#import "CULPath.h"
|
|
10
|
+
#import "CULHost.h"
|
|
11
|
+
#import "CDVPluginResult+CULPlugin.h"
|
|
12
|
+
#import "CDVInvokedUrlCommand+CULPlugin.h"
|
|
13
|
+
#import "CULConfigJsonParser.h"
|
|
14
|
+
|
|
15
|
+
@interface CULPlugin() {
|
|
16
|
+
NSArray *_supportedHosts;
|
|
17
|
+
CDVPluginResult *_storedEvent;
|
|
18
|
+
NSMutableDictionary<NSString *, NSString *> *_subscribers;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@end
|
|
22
|
+
|
|
23
|
+
@implementation CULPlugin
|
|
24
|
+
|
|
25
|
+
#pragma mark Public API
|
|
26
|
+
|
|
27
|
+
- (void)pluginInitialize {
|
|
28
|
+
[self localInit];
|
|
29
|
+
// Can be used for testing.
|
|
30
|
+
// Just uncomment, close the app and reopen it. That will simulate application launch from the link.
|
|
31
|
+
// [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onResume:) name:UIApplicationWillEnterForegroundNotification object:nil];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
//- (void)onResume:(NSNotification *)notification {
|
|
35
|
+
// NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:NSUserActivityTypeBrowsingWeb];
|
|
36
|
+
// [activity setWebpageURL:[NSURL URLWithString:@"http://site2.com/news/page?q=1&v=2#myhash"]];
|
|
37
|
+
//
|
|
38
|
+
// [self handleUserActivity:activity];
|
|
39
|
+
//}
|
|
40
|
+
|
|
41
|
+
- (void)handleOpenURL:(NSNotification*)notification {
|
|
42
|
+
id url = notification.object;
|
|
43
|
+
if (![url isKindOfClass:[NSURL class]]) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
CULHost *host = [self findHostByURL:url];
|
|
48
|
+
if (host) {
|
|
49
|
+
[self storeEventWithHost:host originalURL:url];
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
- (BOOL)handleUserActivity:(NSUserActivity *)userActivity {
|
|
54
|
+
[self localInit];
|
|
55
|
+
|
|
56
|
+
NSURL *launchURL = userActivity.webpageURL;
|
|
57
|
+
CULHost *host = [self findHostByURL:launchURL];
|
|
58
|
+
if (host == nil) {
|
|
59
|
+
return NO;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
[self storeEventWithHost:host originalURL:launchURL];
|
|
63
|
+
|
|
64
|
+
return YES;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
- (void)onAppTerminate {
|
|
68
|
+
_supportedHosts = nil;
|
|
69
|
+
_subscribers = nil;
|
|
70
|
+
_storedEvent = nil;
|
|
71
|
+
|
|
72
|
+
[super onAppTerminate];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#pragma mark Private API
|
|
76
|
+
|
|
77
|
+
- (void)localInit {
|
|
78
|
+
if (_supportedHosts) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_subscribers = [[NSMutableDictionary alloc] init];
|
|
83
|
+
|
|
84
|
+
// Get supported hosts from the config.xml or www/ul.json.
|
|
85
|
+
// For now priority goes to json config.
|
|
86
|
+
_supportedHosts = [self getSupportedHostsFromPreferences];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
- (NSArray<CULHost *> *)getSupportedHostsFromPreferences {
|
|
90
|
+
NSString *jsonConfigPath = [[NSBundle mainBundle] pathForResource:@"ul" ofType:@"json" inDirectory:@"www"];
|
|
91
|
+
if (jsonConfigPath) {
|
|
92
|
+
return [CULConfigJsonParser parseConfig:jsonConfigPath];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return [CULConfigXmlParser parse];
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Store event data for future use.
|
|
100
|
+
* If we are resuming the app - try to consume it.
|
|
101
|
+
*
|
|
102
|
+
* @param host host that matches the launch url
|
|
103
|
+
* @param originalUrl launch url
|
|
104
|
+
*/
|
|
105
|
+
- (void)storeEventWithHost:(CULHost *)host originalURL:(NSURL *)originalUrl {
|
|
106
|
+
_storedEvent = [CDVPluginResult resultWithHost:host originalURL:originalUrl];
|
|
107
|
+
[self tryToConsumeEvent];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Find host entry that corresponds to launch url.
|
|
112
|
+
*
|
|
113
|
+
* @param launchURL url that launched the app
|
|
114
|
+
* @return host entry; <code>nil</code> if none is found
|
|
115
|
+
*/
|
|
116
|
+
- (CULHost *)findHostByURL:(NSURL *)launchURL {
|
|
117
|
+
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:launchURL resolvingAgainstBaseURL:YES];
|
|
118
|
+
CULHost *host = nil;
|
|
119
|
+
for (CULHost *supportedHost in _supportedHosts) {
|
|
120
|
+
NSPredicate *pred = [NSPredicate predicateWithFormat:@"self LIKE[c] %@", supportedHost.name];
|
|
121
|
+
if ([pred evaluateWithObject:urlComponents.host]) {
|
|
122
|
+
host = supportedHost;
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return host;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
#pragma mark Methods to send data to JavaScript
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Try to send event to the web page.
|
|
134
|
+
* If there is a subscriber for the event - it will be consumed.
|
|
135
|
+
* If not - it will stay until someone subscribes to it.
|
|
136
|
+
*/
|
|
137
|
+
- (void)tryToConsumeEvent {
|
|
138
|
+
if (_subscribers.count == 0 || _storedEvent == nil) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
NSString *storedEventName = [_storedEvent eventName];
|
|
143
|
+
for (NSString *eventName in _subscribers) {
|
|
144
|
+
if ([storedEventName isEqualToString:eventName]) {
|
|
145
|
+
NSString *callbackID = _subscribers[eventName];
|
|
146
|
+
[self.commandDelegate sendPluginResult:_storedEvent callbackId:callbackID];
|
|
147
|
+
_storedEvent = nil;
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
#pragma mark Methods, available from JavaScript side
|
|
154
|
+
|
|
155
|
+
- (void)jsSubscribeForEvent:(CDVInvokedUrlCommand *)command {
|
|
156
|
+
NSString *eventName = [command eventName];
|
|
157
|
+
if (eventName.length == 0) {
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
_subscribers[eventName] = command.callbackId;
|
|
162
|
+
[self tryToConsumeEvent];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
- (void)jsUnsubscribeFromEvent:(CDVInvokedUrlCommand *)command {
|
|
166
|
+
NSString *eventName = [command eventName];
|
|
167
|
+
if (eventName.length == 0) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
[_subscribers removeObjectForKey:eventName];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CDVInvokedUrlCommand+CULPlugin.h
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 08.12.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import <Cordova/CDVPlugin.h>
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Category to get the event name from the request, that is sent from JS side.
|
|
11
|
+
*/
|
|
12
|
+
@interface CDVInvokedUrlCommand (CULPlugin)
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get event name from JS request.
|
|
16
|
+
*
|
|
17
|
+
* @return event name
|
|
18
|
+
*/
|
|
19
|
+
- (NSString *)eventName;
|
|
20
|
+
|
|
21
|
+
@end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CDVInvokedUrlCommand+CULPlugin.m
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 08.12.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import "CDVInvokedUrlCommand+CULPlugin.h"
|
|
8
|
+
|
|
9
|
+
@implementation CDVInvokedUrlCommand (CULPlugin)
|
|
10
|
+
|
|
11
|
+
- (NSString *)eventName {
|
|
12
|
+
if (self.arguments.count == 0) {
|
|
13
|
+
return nil;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return self.arguments[0];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CDVPluginResult+CULPlugin.h
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 15.09.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import <Cordova/CDVPlugin.h>
|
|
8
|
+
#import "CULHost.h"
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Category to simplify plugin result generation.
|
|
12
|
+
*/
|
|
13
|
+
@interface CDVPluginResult (CULPlugin)
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get CDVPluginResult instance with information about the launch url that is send to JS.
|
|
17
|
+
*
|
|
18
|
+
* @param host host that corresponds to launch url
|
|
19
|
+
* @param originalURL launching url
|
|
20
|
+
*
|
|
21
|
+
* @return instance of the CDVPluginResult
|
|
22
|
+
*/
|
|
23
|
+
+ (instancetype)resultWithHost:(CULHost *)host originalURL:(NSURL *)originalURL;
|
|
24
|
+
|
|
25
|
+
- (BOOL)isResultForEvent:(NSString *)eventName;
|
|
26
|
+
|
|
27
|
+
- (NSString *)eventName;
|
|
28
|
+
|
|
29
|
+
@end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
//
|
|
2
|
+
// CDVPluginResult+CULPlugin.m
|
|
3
|
+
//
|
|
4
|
+
// Created by Nikolay Demyankov on 15.09.15.
|
|
5
|
+
//
|
|
6
|
+
|
|
7
|
+
#import "CDVPluginResult+CULPlugin.h"
|
|
8
|
+
|
|
9
|
+
#pragma mark keys for the message structure
|
|
10
|
+
|
|
11
|
+
// event name
|
|
12
|
+
static NSString *const EVENT = @"event";
|
|
13
|
+
|
|
14
|
+
// message data block
|
|
15
|
+
static NSString *const DATA = @"data";
|
|
16
|
+
|
|
17
|
+
#pragma mark keys for the message data block
|
|
18
|
+
|
|
19
|
+
// path part from the url
|
|
20
|
+
static NSString *const PATH_ATTRIBUTE = @"path";
|
|
21
|
+
|
|
22
|
+
// scheme from the url
|
|
23
|
+
static NSString *const SCHEME_ATTRIBUTE = @"scheme";
|
|
24
|
+
|
|
25
|
+
// host name from the url
|
|
26
|
+
static NSString *const HOST_ATTRIBUTE = @"host";
|
|
27
|
+
|
|
28
|
+
// hash (fragment) from the url; data after '#'
|
|
29
|
+
static NSString *const HASH_ATTRIBUTE = @"hash";
|
|
30
|
+
|
|
31
|
+
// launch url without any changes
|
|
32
|
+
static NSString *const ORIGIN_ATTRIBUTE = @"url";
|
|
33
|
+
|
|
34
|
+
// query parameters from the url; data after '?'
|
|
35
|
+
static NSString *const URL_PARAMS_ATTRIBUTE = @"params";
|
|
36
|
+
|
|
37
|
+
@implementation CDVPluginResult (CULPlugin)
|
|
38
|
+
|
|
39
|
+
#pragma mark Public API
|
|
40
|
+
|
|
41
|
+
+ (instancetype)resultWithHost:(CULHost *)host originalURL:(NSURL *)originalURL {
|
|
42
|
+
NSDictionary *message = [self prepareMessageForHost:host originalURL:originalURL];
|
|
43
|
+
|
|
44
|
+
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:message];
|
|
45
|
+
[result setKeepCallbackAsBool:YES];
|
|
46
|
+
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
- (BOOL)isResultForEvent:(NSString *)eventName {
|
|
51
|
+
NSString *eventInMessage = [self eventName];
|
|
52
|
+
if (eventInMessage.length == 0 || eventName.length == 0) {
|
|
53
|
+
return NO;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return [eventInMessage isEqualToString:eventName];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (NSString *)eventName {
|
|
60
|
+
if (self.message == nil || ![self.message isKindOfClass:[NSDictionary class]]) {
|
|
61
|
+
return nil;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
NSDictionary *data = self.message;
|
|
65
|
+
|
|
66
|
+
return data[EVENT];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#pragma mark Private API
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Create dictionary for message, that should be send to JS.
|
|
73
|
+
* Holds event name and event details.
|
|
74
|
+
*
|
|
75
|
+
* @param host host entry that corresponds to the url
|
|
76
|
+
* @param originalURL launch url
|
|
77
|
+
*
|
|
78
|
+
* @return messasge dictionary
|
|
79
|
+
*/
|
|
80
|
+
+ (NSDictionary *)prepareMessageForHost:(CULHost *)host originalURL:(NSURL *)originalURL {
|
|
81
|
+
NSURLComponents *urlComponents = [NSURLComponents componentsWithURL:originalURL resolvingAgainstBaseURL:YES];
|
|
82
|
+
NSMutableDictionary *messageDict = [[NSMutableDictionary alloc] init];
|
|
83
|
+
|
|
84
|
+
// set event name
|
|
85
|
+
NSString *eventName = [self getEventNameBasedOnHost:host originalURLComponents:urlComponents];
|
|
86
|
+
[messageDict setObject:eventName forKey:EVENT];
|
|
87
|
+
|
|
88
|
+
// set event details
|
|
89
|
+
NSDictionary *data = [self getDataDictionaryForURLComponents:urlComponents];
|
|
90
|
+
[messageDict setObject:data forKey:DATA];
|
|
91
|
+
|
|
92
|
+
return messageDict;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Find event name based on the launch url and corresponding host entry.
|
|
97
|
+
*
|
|
98
|
+
* @param host host entry
|
|
99
|
+
* @param urlComponents launch url components
|
|
100
|
+
*
|
|
101
|
+
* @return event name
|
|
102
|
+
*/
|
|
103
|
+
+ (NSString *)getEventNameBasedOnHost:(CULHost *)host originalURLComponents:(NSURLComponents *)urlComponents {
|
|
104
|
+
NSString *eventName = host.event;
|
|
105
|
+
NSArray<CULPath *> *hostPaths = host.paths;
|
|
106
|
+
NSString *originalPath = urlComponents.path.lowercaseString;
|
|
107
|
+
|
|
108
|
+
if (originalPath.length == 0) {
|
|
109
|
+
return eventName;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
for (CULPath *hostPath in hostPaths) {
|
|
113
|
+
NSRange range = [originalPath rangeOfString:hostPath.url options:NSRegularExpressionSearch];
|
|
114
|
+
if (range.location != NSNotFound && range.location == 0) {
|
|
115
|
+
eventName = hostPath.event;
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return eventName;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Create dictionary with event details.
|
|
125
|
+
*
|
|
126
|
+
* @param originalURLComponents launch url components
|
|
127
|
+
*
|
|
128
|
+
* @return dictionary with url information
|
|
129
|
+
*/
|
|
130
|
+
+ (NSDictionary *)getDataDictionaryForURLComponents:(NSURLComponents *)originalURLComponents {
|
|
131
|
+
NSMutableDictionary *dataDict = [[NSMutableDictionary alloc] init];
|
|
132
|
+
|
|
133
|
+
NSString *originUrl = originalURLComponents.URL.absoluteString;
|
|
134
|
+
NSString *host = originalURLComponents.host ? originalURLComponents.host : @"";
|
|
135
|
+
NSString *path = originalURLComponents.path ? originalURLComponents.path : @"";
|
|
136
|
+
NSString *scheme = originalURLComponents.scheme ? originalURLComponents.scheme : @"";
|
|
137
|
+
NSString *hash = originalURLComponents.fragment ? originalURLComponents.fragment : @"";
|
|
138
|
+
|
|
139
|
+
[dataDict setObject:originUrl forKey:ORIGIN_ATTRIBUTE];
|
|
140
|
+
[dataDict setObject:host forKey:HOST_ATTRIBUTE];
|
|
141
|
+
[dataDict setObject:path forKey:PATH_ATTRIBUTE];
|
|
142
|
+
[dataDict setObject:scheme forKey:SCHEME_ATTRIBUTE];
|
|
143
|
+
[dataDict setObject:hash forKey:HASH_ATTRIBUTE];
|
|
144
|
+
|
|
145
|
+
// set query params
|
|
146
|
+
NSArray<NSURLQueryItem *> *queryItems = originalURLComponents.queryItems;
|
|
147
|
+
NSMutableDictionary<NSString *, NSString *> *qParams = [[NSMutableDictionary alloc] init];
|
|
148
|
+
for (NSURLQueryItem *qItem in queryItems) {
|
|
149
|
+
NSString *value = qItem.value ? qItem.value : @"";
|
|
150
|
+
[qParams setValue:value forKey:qItem.name];
|
|
151
|
+
}
|
|
152
|
+
[dataDict setObject:qParams forKey:URL_PARAMS_ATTRIBUTE];
|
|
153
|
+
|
|
154
|
+
return dataDict;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
@end
|