How to share my current location to UIActivityViewController?

前端 未结 8 1342
别那么骄傲
别那么骄傲 2020-12-05 12:32

I know i can add things like text, URL, images to UIActivityViewController , but how to add my current location with a thumbnail of my location like in the tweet shown below

相关标签:
8条回答
  • 2020-12-05 12:33

    To share location like that you need to create a vcf file for that location... I just spent my whole day trying to do the same and gathering informations here and there managed to find out that apple does it in maps using a file name like "address you share.loc.vcf"

    You basically need to get the current location using the CLLocationManager, then use a CLGeocoder to get the address from the location you retrieved with the Location Manager.

    The CLGeocoder gets you a CLPlacemark that you can make into a MKPlacemark.

    You will use the addressDictionary stored in there

    With this info you can create an ABRecordRef using ABPersonCreate, store all the data for that location in there and then get the vcd data using ABPersonCreateVCardRepresentationWithPeople

    You'll need to also add a map url, just share a location with yourself from maps.app and look into the .vcf for the url structure...

    transform that data into an NSString and save to file.

    Create an NSURL to that file and share it with the UIActivityViewController...

    Pretty tedious work but it's definitely working great for me...

    0 讨论(0)
  • 2020-12-05 12:42

    I've updated @naturaln0va's answer to Swift 3:
    https://gist.github.com/ElegyD/510a17904917a7e7326254b824da1b2f

    Just copy & paste somewhere and use it like so:

    let coordinate = CLLocationCoordinate2D(latitude: 52.520007, longitude: 13.404954)
    let vCardURL = LocationVCard.vCardUrl(from: coordinate, with: "Berlin")
    let activityViewController = UIActivityViewController(activityItems: [vCardURL], applicationActivities: nil)
    present(activityViewController, animated: true, completion: nil)
    
    0 讨论(0)
  • 2020-12-05 12:49

    My variant in Swift 2

           let passDictionaryInfo = placeMark.addressDictionary as! [String: AnyObject]
    
           @IBAction func shareLocation(sender: UIBarButtonItem) {
    //        print(receivedDictionary)
            let postalAdress = CNMutablePostalAddress()
            postalAdress.street = receivedDictionary["Name"] as! String
            postalAdress.city = receivedDictionary["City"] as! String
            postalAdress.state = receivedDictionary["State"] as! String
            postalAdress.postalCode = receivedDictionary["ZIP"] as! String
            postalAdress.country = receivedDictionary["Country"] as! String
            postalAdress.ISOCountryCode = receivedDictionary["CountryCode"] as! String
    
            let streetName = receivedDictionary["Name"] as! String
    
            let urlAddress = receivedDictionary["FormattedAddressLines"] as! [String]
    //        print(urlAddress)
            let postalContact = CNLabeledValue(label: streetName, value: postalAdress)
            let urlAddressContact = CNLabeledValue(label: "map url", value: "http://maps.apple.com/maps?address=\(urlAddress.description)")
    
            let contact = CNMutableContact()
            contact.contactType = .Organization
            contact.organizationName = streetName
            contact.departmentName = streetName
            contact.postalAddresses = [postalContact]
            contact.urlAddresses = [urlAddressContact]
    
            // create path
    
            let directory = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
    
            let path = directory.first!.path!.stringByAppendingString("/\(streetName).loc.vcf")
    //        print(path)
    
            do {
                let contactData = try CNContactVCardSerialization.dataWithContacts([contact])
    
                contactData.writeToFile(path, atomically: true)
    
                let url = NSURL(fileURLWithPath: path)
    //            print(url)
                let activityViewController = UIActivityViewController(activityItems: [url], applicationActivities: nil)
                presentViewController(activityViewController, animated: true, completion: nil)
            } catch {
                print("CNContactVCardSerialization cannot save address")
            }
        }
    
    0 讨论(0)
  • 2020-12-05 12:50

    I have a complete example of code and all the important classes/methods to do this. I know the answer is very late, but this may help someone in the future:

    - (void)shareTab
    {
        PFGeoPoint *geoPoint = self.vidgeoObject[kParseLocation];
        NSString *coordinates = [NSString stringWithFormat:@"http://maps.apple.com/maps?q=%f,%f",  geoPoint.latitude, geoPoint.longitude];
        CLLocation *userLocation = [[CLLocation alloc] initWithLatitude:geoPoint.latitude longitude:geoPoint.longitude];
        CLGeocoder *geocoder;
        geocoder = [[CLGeocoder alloc]init];
    
        [geocoder reverseGeocodeLocation:userLocation completionHandler:^(NSArray *placemarks, NSError *error)
        {
            CLPlacemark *rootPlacemark = placemarks[0];
            MKPlacemark *evolvedPlacemark = [[MKPlacemark alloc]initWithPlacemark:rootPlacemark];
    
            ABRecordRef persona = ABPersonCreate();
            ABRecordSetValue(persona, kABPersonFirstNameProperty, (__bridge CFTypeRef)(evolvedPlacemark.name), nil);
            ABMutableMultiValueRef multiHome = ABMultiValueCreateMutable(kABMultiDictionaryPropertyType);
    
            bool didAddHome = ABMultiValueAddValueAndLabel(multiHome, (__bridge CFTypeRef)(evolvedPlacemark.addressDictionary), kABHomeLabel, NULL);
    
            if(didAddHome)
            {
                ABRecordSetValue(persona, kABPersonAddressProperty, multiHome, NULL);
    
                NSLog(@"Address saved.");
            }
    
            NSArray *individual = [[NSArray alloc]initWithObjects:(__bridge id)(persona), nil];
            CFArrayRef arrayRef = (__bridge CFArrayRef)individual;
            NSData *vcards = (__bridge NSData *)ABPersonCreateVCardRepresentationWithPeople(arrayRef);
    
            NSString* vcardString;
            vcardString = [[NSString alloc] initWithData:vcards encoding:NSASCIIStringEncoding];
            NSLog(@"%@",vcardString);
    
    
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
            NSString *documentsDirectory = [paths objectAtIndex:0]; // Get documents directory
    
            NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"pin.loc.vcf"];
            [vcardString writeToFile:filePath
                                  atomically:YES encoding:NSUTF8StringEncoding error:&error];
    
            NSURL *url =  [NSURL fileURLWithPath:filePath];
            NSLog(@"url> %@ ", [url absoluteString]);
    
    
            // Share Code //
            NSArray *itemsToShare = [[NSArray alloc] initWithObjects: url, nil] ;
            UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:itemsToShare applicationActivities:nil];
            activityVC.excludedActivityTypes = @[UIActivityTypePrint,
                                                 UIActivityTypeCopyToPasteboard,
                                                 UIActivityTypeAssignToContact,
                                                 UIActivityTypeSaveToCameraRoll,
                                                 UIActivityTypePostToWeibo];
    
            if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone)
            {
                [self presentViewController:activityVC animated:YES completion:nil];
            } else
            {
            popControl = [[UIPopoverController alloc] initWithContentViewController:activityVC];
            }
    
        }];
    
    }
    
    0 讨论(0)
  • I have created a Swift alternative to this that persists a vCard file to the caches directory that you can checkout at: https://gist.github.com/naturaln0va/e1fed3f1d32ecf951aac.

    The vCard structure is similar to whoKnows' answer above.

    let vCardString = [
        "BEGIN:VCARD",
        "VERSION:3.0",
        "N:;Shared Location;;;",
        "FN:Shared Location",
        "item1.URL;type=pref:http://maps.apple.com/?ll=\(coordinate.latitude),\(coordinate.longitude)",
        "item1.X-ABLabel:map url",
        "END:VCARD"
    ].joinWithSeparator("\n")
    
    0 讨论(0)
  • 2020-12-05 12:55

    Solution using Swift 4.2 and CNContactVCardSerialization

     func vCardFilePath(from placemark: CLPlacemark) -> String? {
            let cnAddress = CNMutablePostalAddress()
            cnAddress.city = placemark.locality ?? ""
            cnAddress.country = placemark.country ?? ""
            cnAddress.postalCode = placemark.postalCode ?? ""
            cnAddress.isoCountryCode = placemark.isoCountryCode ?? ""
            cnAddress.state = placemark.administrativeArea ?? ""
            cnAddress.street = placemark.thoroughfare ?? ""
            let labelledAddress = CNLabeledValue<CNPostalAddress>(label: CNLabelOther, value: cnAddress)
    
            let abPerson = CNMutableContact()
            abPerson.givenName = locationName ?? ""
            abPerson.postalAddresses = [labelledAddress]
    
            if let coords = position?.coordinate,
                let loc = locationName?.addingPercentEncoding(withAllowedCharacters: .whitespacesAndNewlines) {
                let url = "https://maps.apple.com/?ll=\(coords.latitude),\(coords.longitude)&q=\(loc)" as NSString
                let urlAddress = CNLabeledValue<NSString>(label: CNLabelHome, value: url)
                abPerson.urlAddresses = [urlAddress]
            }
    
            guard let vCards = try? CNContactVCardSerialization.data(with: [abPerson]) else {
                print("Couldn't extract vCards data")
                return nil
            }
            let vCardString = String(data: vCards, encoding: .utf8)
    
            //Store the vCard file
            let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
            let documentsDirectory = paths[0]
            let filePath = "\(documentsDirectory)/shareLocation.vcf"
    
            do {
                try vCardString?.write(toFile: filePath, atomically: false, encoding: .utf8)
            } catch _ {
                print("Couldn't write location .vcf file")
                return nil
            }
            return filePath
        }
    
    0 讨论(0)
提交回复
热议问题