(iOS) Implementing map.addKmlOverlay()
MODIFY
plugin.xml
plugin.xml
<?xml version='1.0' encoding='utf-8'?>
-<plugin id="cordova-plugin-googlemaps" version="2.1.2-beta-20171122-2100" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
+<plugin id="cordova-plugin-googlemaps" version="2.1.2-beta-20171124-0000" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
<name>cordova-plugin-googlemaps</name>
<js-module name="BaseClass" src="www/BaseClass.js">
<runs />

MODIFY
src/android/plugin/google/maps/PluginKmlOverlay.java
src/android/plugin/google/maps/PluginKmlOverlay.java
@@ -47,6 +47,7 @@ public class PluginKmlOverlay extends MyPlugin implements MyPluginInterface {
key,
styleurl,
color,
+ outline,
width,
fill,
name,
@@ -338,6 +339,7 @@ public class PluginKmlOverlay extends MyPlugin implements MyPluginInterface {
case name:
case width:
case color:
+ case outline:
case fill:
case description:
if (currentNode != null) {

MODIFY
src/ios/GoogleMaps/PluginKmlOverlay.h
src/ios/GoogleMaps/PluginKmlOverlay.h
@property (nonatomic) BOOL initialized;
@property (nonatomic, strong) GoogleMapsViewController* mapCtrl;
-@property (nonatomic, strong) NSString* kmlId;
-@property (nonatomic, strong) UIView* _loadingView;
-@property (nonatomic, strong) UIActivityIndicatorView *spinner;
-- (void)createKmlOverlay:(CDVInvokedUrlCommand*)command;
+- (void)create:(CDVInvokedUrlCommand*)command;
@end

MODIFY
src/ios/GoogleMaps/PluginKmlOverlay.m
src/ios/GoogleMaps/PluginKmlOverlay.m
{
}
--(void)createKmlOverlay:(CDVInvokedUrlCommand *)command
+-(void)create:(CDVInvokedUrlCommand *)command
{
+
+ [[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSDictionary *json = [command.arguments objectAtIndex:1];
NSError *error;
- TBXML *tbxml = [TBXML alloc];// initWithXMLFile:urlStr error:&error];
NSString *urlStr = [json objectForKey:@"url"];
- NSRange range = [urlStr rangeOfString:@"://"];
- if (range.location == NSNotFound) {
- range = [urlStr rangeOfString:@"www/"];
- if (range.location == NSNotFound) {
- range = [urlStr rangeOfString:@"/"];
- if (range.location != 0) {
+ NSRange range;
+ if (![urlStr hasPrefix:@"http"]) {
+ NSLog(@"--->url = %@", urlStr);
+
+ if (![urlStr containsString:@"://"] &&
+ ![urlStr hasPrefix:@"/"] &&
+ ![urlStr hasPrefix:@"www"] &&
+ ![urlStr hasPrefix:@"./"] &&
+ ![urlStr hasPrefix:@"../"]) {
urlStr = [NSString stringWithFormat:@"./%@", urlStr];
}
+ NSLog(@"--->url = %@", urlStr);
+
+ if ([urlStr hasPrefix:@"./"] || [urlStr hasPrefix:@"../"]) {
+ NSError *error = nil;
+
+ // replace repeated "./" (i.e ./././test.png)
+ NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(\\.\\/)+" options:NSRegularExpressionCaseInsensitive error:&error];
+ urlStr = [regex stringByReplacingMatchesInString:urlStr options:0 range:NSMakeRange(0, [urlStr length]) withTemplate:@"./"];
+
+
+ // Get the current URL, then calculate the relative path.
+ CDVViewController *cdvViewController = (CDVViewController*)self.viewController;
+
+ id webview = cdvViewController.webView;
+ NSString *clsName = [webview className];
+ NSURL *url;
+ NSString *currentURL;
+ if ([clsName isEqualToString:@"UIWebView"]) {
+ //------------------------------------------
+ // UIWebView
+ //------------------------------------------
+ url = ((UIWebView *)cdvViewController.webView).request.URL;
+ currentURL = url.absoluteString;
+
+ } else {
+ //------------------------------------------
+ // WKWebView
+ //------------------------------------------
+ NSURL *url = [webview URL];
+ currentURL = url.absoluteString;
+ if (![[url lastPathComponent] isEqualToString:@"/"]) {
+ currentURL = [currentURL stringByReplacingOccurrencesOfString:[url lastPathComponent] withString:@""];
+ }
}
+ // remove page unchor (i.e index.html#page=test, index.html?key=value)
+ regex = [NSRegularExpression regularExpressionWithPattern:@"[#\\?].*$" options:NSRegularExpressionCaseInsensitive error:&error];
+ currentURL = [regex stringByReplacingMatchesInString:currentURL options:0 range:NSMakeRange(0, [currentURL length]) withTemplate:@""];
+
+ // remove file name (i.e /index.html)
+ regex = [NSRegularExpression regularExpressionWithPattern:@"\\/[^\\/]+\\.[^\\/]+$" options:NSRegularExpressionCaseInsensitive error:&error];
+ currentURL = [regex stringByReplacingMatchesInString:currentURL options:0 range:NSMakeRange(0, [currentURL length]) withTemplate:@""];
+
+ if (![currentURL hasSuffix:@"/"]) {
+ currentURL = [NSString stringWithFormat:@"%@/", currentURL];
}
+ urlStr = [NSString stringWithFormat:@"%@%@", currentURL, urlStr];
- range = [urlStr rangeOfString:@"./"];
- if (range.location != NSNotFound) {
- SEL requestSelector = NSSelectorFromString(@"request");
- SEL urlSelector = NSSelectorFromString(@"URL");
- NSString *currentPath = @"";
- if ([self.webView respondsToSelector:requestSelector]) {
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self.webView class] instanceMethodSignatureForSelector:requestSelector]];
- [invocation setSelector:requestSelector];
- [invocation setTarget:self.webView];
- [invocation invoke];
- NSURLRequest *request;
- [invocation getReturnValue:&request];
- currentPath = [request.URL absoluteString];
- } else if ([self.webView respondsToSelector:urlSelector]) {
- NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[[self.webView class] instanceMethodSignatureForSelector:urlSelector]];
- [invocation setSelector:urlSelector];
- [invocation setTarget:self.webView];
- [invocation invoke];
- NSURL *URL;
- [invocation getReturnValue:&URL];
- currentPath = [URL absoluteString];
- }
- NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"[^\\/]*$" options:NSRegularExpressionCaseInsensitive error:&error];
- currentPath= [regex stringByReplacingMatchesInString:currentPath options:0 range:NSMakeRange(0, [currentPath length]) withTemplate:@""];
- urlStr = [urlStr stringByReplacingOccurrencesOfString:@"./" withString:currentPath];
+ // remove file name (i.e /index.html)
+ regex = [NSRegularExpression regularExpressionWithPattern:@"(\\/\\.\\/+)+" options:NSRegularExpressionCaseInsensitive error:&error];
+ urlStr = [regex stringByReplacingMatchesInString:urlStr options:0 range:NSMakeRange(0, [urlStr length]) withTemplate:@"/"];
+
+ urlStr = [urlStr stringByReplacingOccurrencesOfString:@"%20" withString:@" "];
+
+ if (self.mapCtrl.debuggable) {
+ NSLog(@"urlStr = %@", urlStr);
+ }
}
range = [urlStr rangeOfString:@"cdvfile://"];
error = [NSError errorWithDomain:@"world" code:200 userInfo:details];
}
}
+ }
if (self.mapCtrl.debuggable) {
NSLog(@"urlStr = %@", urlStr);
}
-
+ [self.mapCtrl.executeQueue addOperationWithBlock:^{
+ NSError *error;
+ TBXML *tbxml = [TBXML alloc];// initWithXMLFile:urlStr error:&error];
if ([urlStr hasPrefix:@"http://"] || [urlStr hasPrefix:@"https://"]) {
NSURLRequest *req = [NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]];
bool valid = [NSURLConnection canHandleRequest:req];
return;
}
- if ([json valueForKey:@"kmlId"]) {
- self.kmlId = [json valueForKey:@"kmlId"];
+ NSMutableDictionary *styles = [NSMutableDictionary dictionary];
+ NSMutableDictionary *kmlData = [self parseXML:tbxml.rootXMLElement styles:styles];
+
+ NSMutableArray *kmlChildren = [kmlData objectForKey:@"children"];
+ NSMutableDictionary *document = [kmlChildren objectAtIndex:0];
+
+ NSMutableDictionary *finalResult = [NSMutableDictionary dictionary];
+ [finalResult setObject:document forKey:@"root"];
+ [finalResult setObject:styles forKey:@"styles"];
+ NSLog(@"kmlData = %@", finalResult);
+
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:finalResult];
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+
+ }];
+ }];
+
+
+}
+
+-(NSMutableDictionary *)parseXML:(TBXMLElement *)rootElement styles:(NSMutableDictionary *)styles
+{
+
+ NSError *error = nil;
+ NSMutableDictionary *result = [NSMutableDictionary dictionary];
+ NSString *tagName = [[TBXML elementName:rootElement] lowercaseString];
+
+ NSLog(@"---> tagName = %@", tagName);
+
+ if ([@"style" isEqualToString:tagName] ||
+ [@"stylemap" isEqualToString:tagName]) {
+ NSString *attrName;
+ [result setObject:tagName forKey:@"tagName"];
+ TBXMLAttribute *attribute = rootElement->firstAttribute;
+ NSString *value;
+ NSString *idName = @"__default__";
+ while (attribute) {
+ attrName = [[TBXML attributeName:attribute] lowercaseString];
+ value = [TBXML attributeValue:attribute];
+ if ([@"id" isEqualToString:attrName]) {
+ idName = [NSString stringWithFormat:@"#%@", value];
+ }
+ [result setObject:value forKey:attrName];
+ attribute = attribute->next;
+ }
+
+
+ NSMutableArray *children = [NSMutableArray array];
+ TBXMLElement *childNode = rootElement->firstChild;
+ while (childNode) {
+
+ NSMutableDictionary *node = [self parseXML:childNode styles:styles];
+ if (node) {
+ if ([node objectForKey:@"value"]) {
+ [result setObject:[node objectForKey:@"value"] forKey:[node objectForKey:@"tagName"]];
} else {
- self.kmlId = [NSString stringWithFormat:@"kml%d-", arc4random()];
- }
-
- //Show the spinner
- self._loadingView = [[UIView alloc] init];
- [self._loadingView setFrameWithInt:0 top:0 width:self.mapCtrl.view.frame.size.width height:self.mapCtrl.view.frame.size.height];
- self._loadingView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
- self._loadingView.clipsToBounds = YES;
- self._loadingView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- //Create the dialog
- CGRect dialogRect = self.mapCtrl.view.frame;
- dialogRect.size.width = dialogRect.size.width * 0.8;
- dialogRect.size.height = 80;
-
- UIView *licenseDialog = [[UIView alloc] initWithFrame:dialogRect];
- licenseDialog.center = CGPointMake(self._loadingView.frame.size.width / 2, self._loadingView.frame.size.height / 2);
- [licenseDialog setBackgroundColor:[UIColor blackColor]];
- [licenseDialog.layer setBorderColor:[UIColor colorWithRed:255 green:255 blue:255 alpha:0.5].CGColor];
- [licenseDialog.layer setBorderWidth:1.0];
- [licenseDialog.layer setCornerRadius:10];
- licenseDialog.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleHeight;
- [self._loadingView addSubview:licenseDialog];
-
- self.spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
- self.spinner.center = CGPointMake(licenseDialog.frame.size.width / 2, licenseDialog.frame.size.height / 2 + 10);
- [licenseDialog addSubview:self.spinner];
- self.spinner.hidesWhenStopped = YES;
- [self.spinner startAnimating];
-
- UILabel *message = [[UILabel alloc] initWithFrame:licenseDialog.frame];
- message.center = CGPointMake(licenseDialog.frame.size.width / 2, licenseDialog.frame.size.height / 2 - 20);
- message.backgroundColor = [UIColor clearColor];
- message.textColor = [UIColor whiteColor];
- message.adjustsFontSizeToFitWidth = YES;
- message.textAlignment = NSTextAlignmentCenter;
- message.text = @"Please wait...";
- [licenseDialog addSubview:message];
-
- [self.mapCtrl.view addSubview:self._loadingView];
+ [children addObject:node];
+ }
+ }
+ childNode = childNode->nextSibling;
+ }
+ if ([children count] > 0) {
+ [result setObject:children forKey:@"children"];
+ }
+
+ [styles setObject:result forKey:idName];
+ return nil;
+ }
+
+ else if (
+ [@"linestring" isEqualToString:tagName] ||
+ [@"linestyle" isEqualToString:tagName] ||
+ [@"polystyle" isEqualToString:tagName] ||
+ [@"pair" isEqualToString:tagName] ||
+ [@"point" isEqualToString:tagName] ||
+ [@"outerboundaryis" isEqualToString:tagName] ||
+ [@"innerboundaryis" isEqualToString:tagName] ||
+ [@"polygon" isEqualToString:tagName] ||
+ [@"icon" isEqualToString:tagName] ||
+ [@"groundoverlay" isEqualToString:tagName] ||
+ [@"latlonbox" isEqualToString:tagName] ||
+ [@"link" isEqualToString:tagName] ||
+ [@"placemark" isEqualToString:tagName] ||
+ [@"multigeometry" isEqualToString:tagName] ||
+ [@"folder" isEqualToString:tagName] ||
+ [@"kml" isEqualToString:tagName] ||
+ [@"document" isEqualToString:tagName] ||
+ [@"networklink" isEqualToString:tagName]) {
+
+
+ [result setObject:tagName forKey:@"tagName"];
+ NSMutableArray *children = [NSMutableArray array];
+ TBXMLElement *childNode = rootElement->firstChild;
+ while (childNode) {
- // Parse the kml file
- [self parseKML:tbxml command:command];
+ NSMutableDictionary *node = [self parseXML:childNode styles:styles];
+ if (node) {
+ if ([node objectForKey:@"value"]) {
+ [result setObject:[node objectForKey:@"value"] forKey:[node objectForKey:@"tagName"]];
+ } else {
+ [children addObject:node];
+ }
+ }
+ childNode = childNode->nextSibling;
+ }
+ if ([children count] > 0) {
+ [result setObject:children forKey:@"children"];
+ }
+ }
+ else if ([@"visibility" isEqualToString:tagName] ||
+ [@"north" isEqualToString:tagName] ||
+ [@"east" isEqualToString:tagName] ||
+ [@"west" isEqualToString:tagName] ||
+ [@"south" isEqualToString:tagName] ||
+ [@"href" isEqualToString:tagName] ||
+ [@"key" isEqualToString:tagName] ||
+ [@"styleurl" isEqualToString:tagName] ||
+ [@"name" isEqualToString:tagName] ||
+ [@"width" isEqualToString:tagName] ||
+ [@"color" isEqualToString:tagName] ||
+ [@"fill" isEqualToString:tagName] ||
+ [@"description" isEqualToString:tagName]) {
+
+ [result setObject:tagName forKey:@"tagName"];
+ [result setObject:[TBXML textForElement:rootElement] forKey:@"value"];
+ }
+
+ else if ([@"coordinates" isEqualToString:tagName]) {
+ NSString *txt = [TBXML textForElement:rootElement];
+
+ NSRegularExpression *regex = [NSRegularExpression
+ regularExpressionWithPattern:@"\\s+"
+ options:NSRegularExpressionUseUnixLineSeparators
+ error:&error];
+ txt = [regex stringByReplacingMatchesInString:txt options:0 range:NSMakeRange(0, [txt length]) withTemplate:@"\n"];
+
+ regex = [NSRegularExpression
+ regularExpressionWithPattern:@"\n+"
+ options:NSRegularExpressionUseUnixLineSeparators
+ error:&error];
+ txt = [regex stringByReplacingMatchesInString:txt options:0 range:NSMakeRange(0, [txt length]) withTemplate:@"\n"];
+ NSMutableArray *latLngList = [NSMutableArray array];
+ NSMutableArray *lines = [NSMutableArray arrayWithArray:[txt componentsSeparatedByString:@"\n"]];
+ for (int i = 0; i < [lines count]; i++) {
+ NSString *line = [lines objectAtIndex:i];
+ if (![line isEqualToString:@""]) {
+ NSArray *tmpArry = [line componentsSeparatedByString:@","];
+ NSMutableDictionary *latLng = [NSMutableDictionary dictionary];
+ [latLng setObject:[tmpArry objectAtIndex:1] forKey:@"lat"];
+ [latLng setObject:[tmpArry objectAtIndex:0] forKey:@"lng"];
+ [latLngList addObject:latLng];
+ }
+ }
+
+ [result setObject:tagName forKey:@"tagName"];
+ [result setObject:latLngList forKey:@"value"];
+ } else {
+
+ [result setObject:tagName forKey:@"tagName"];
+ [result setObject:[TBXML textForElement:rootElement] forKey:@"value"];
+ }
+
+ return result;
+
+/*
+ if (childNode) {
+ while(childNode) {
+ NSMutableDictionary *tmp = [self parseXML:childNode];
+ TBXMLAttribute *attribute = childNode->firstAttribute;
+ while (attribute) {
+ attrName = [NSString stringWithFormat:@"_%@", [[TBXML attributeName:attribute] lowercaseString]];
+ tmp[attrName] = [TBXML attributeValue:attribute];
+ attribute = attribute->next;
+ }
+
+ [children addObject: tmp];
+ childNode = childNode->nextSibling;
+ }
+ } else if ([TBXML textForElement:rootElement] != nil) {
+ result[tagName] = [TBXML textForElement:rootElement];
+ }
+ if ([children count] > 0) {
+ result[@"children"] = children;
}
--(void)parseKML:(TBXML *)tbxml command:(CDVInvokedUrlCommand *)command
+ */
+}
+
+-(void)parseKML_old:(TBXML *)tbxml command:(CDVInvokedUrlCommand *)command
{
- NSString *idPrefix = [NSString stringWithFormat:@"%@-", self.kmlId];
+ NSString *idPrefix = @"";
dispatch_queue_t gueue = dispatch_queue_create("plugin.google.maps.Map.createKmlOverlay", NULL);
dispatch_async(gueue, ^{
//NSLog(@"%@", [[TBXML elementName:tbxml.rootXMLElement] lowercaseString]);
//NSLog(@"-----------------> parseXML");
- kmlData = [self parseXML:tbxml.rootXMLElement];
+ //kmlData = [self parseXML:tbxml.rootXMLElement];
//NSLog(@"%@", kmlData);
});
viewportRef:&defaultViewport];
}
- //Close the loading view
- dispatch_sync(dispatch_get_main_queue(), ^{
- [self.spinner stopAnimating];
- [self._loadingView removeFromSuperview];
- [self._loadingView removeFromSuperview];
- });
-
//Change the viewport
NSDictionary *json = [command.arguments objectAtIndex:1];
}
- CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:self.kmlId];
+ CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:@""];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
});
if (linkUrl != nil) {
NSMutableDictionary *options2 = [NSMutableDictionary dictionary];
[options2 setObject:linkUrl forKey:@"url"];
- [options2 setObject:self.kmlId forKey:@"kmlId"];
+ [options2 setObject:@"" forKey:@"kmlId"];
[self _implementToMap:@"KmlOverlay" options:options2 needJSCallback:NO];
}
-
- [self.spinner stopAnimating];
- [self._loadingView removeFromSuperview];
}
});
//Add callback
NSString* jsString = [NSString stringWithFormat:@"cordova.callbacks['%@']={'success': function(result) {plugin.google.maps.Map._onKmlEvent('add', '%@', '%@', result, %@);}, 'fail': null};",
- callbackId, className, self.kmlId, jsonString];
+ callbackId, className, @"", jsonString];
[self performSelectorOnMainThread:@selector(evalJsHelper:) withObject:jsString waitUntilDone:YES];
}
}
--(NSMutableDictionary *)parseXML:(TBXMLElement *)rootElement
-{
-
- TBXMLElement *childNode = rootElement->firstChild;
- NSString *tagName = [[TBXML elementName:rootElement] lowercaseString];
- NSMutableDictionary *result = [NSMutableDictionary dictionary];
- NSMutableArray *children = [NSMutableArray array];
- result[@"_tag"] = tagName;
- NSString *attrName;
-
- if (childNode) {
- while(childNode) {
- NSMutableDictionary *tmp = [self parseXML:childNode];
- TBXMLAttribute *attribute = childNode->firstAttribute;
- while (attribute) {
- attrName = [NSString stringWithFormat:@"_%@", [[TBXML attributeName:attribute] lowercaseString]];
- tmp[attrName] = [TBXML attributeValue:attribute];
- attribute = attribute->next;
- }
-
- [children addObject: tmp];
- childNode = childNode->nextSibling;
- }
- } else if ([TBXML textForElement:rootElement] != nil) {
- result[tagName] = [TBXML textForElement:rootElement];
- }
- if ([children count] > 0) {
- result[@"children"] = children;
- }
- return result;
-}
@end

(iOS) Implementing map.addKmlOverlay()