如何将我当前的位置分享给UIActivityViewController?

时间:2013-11-19 06:35:20

标签: ios uiactivityviewcontroller

我知道我可以向UIActivityViewController添加文本,URL,图像等内容,但是如何使用我的位置缩略图添加我当前的位置,如下面显示的推文?换句话说,如何在UIActivityViewController中共享坐标“latitude,longitude”?

由于

a tweet with location

8 个答案:

答案 0 :(得分:7)

我有一个完整的代码示例以及执行此操作的所有重要类/方法。我知道答案很晚,但这有助于将来的某些人:

- (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];
        }

    }];

}

答案 1 :(得分:3)

我创建了一个Swift替代方法,将vCard文件保存到缓存目录,您可以在https://gist.github.com/naturaln0va/e1fed3f1d32ecf951aac结帐。

vCard结构类似于whoKnows'回答上面。

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")

答案 2 :(得分:2)

我在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")
        }
    }

答案 3 :(得分:1)

要共享这样的位置,你需要为该位置创建一个vcf文件...我只是花了一整天时间尝试做同样的事情并在这里收集信息并且设法发现苹果在地图中使用了文件名如“address you share.loc.vcf”

您基本上需要使用CLLocationManager获取当前位置,然后使用CLGeocoder从您使用位置管理器检索的位置获取地址。

CLGeocoder会为您提供一个CLPlacemark,您可以将其制作成MKPlacemark。

您将使用存储在那里的addressDictionary

使用此信息,您可以使用ABPersonCreate创建ABRecordRef,将该位置的所有数据存储在那里,然后使用ABPersonCreateVCardRepresentationWithPeople获取vcd数据

您还需要添加一个地图网址,只需从maps.app与您分享一个位置,然后查看.vcf以获取网址结构...

将该数据转换为NSString并保存到文件。

为该文件创建一个NSURL并与UIActivityViewController ...

共享

相当繁琐的工作,但它对我来说绝对有用......

答案 4 :(得分:1)

另外两个答案使用复杂的AddressBook框架来创建vCard。这样做比较容易:

NSString *vcardString = [NSString stringWithFormat:@"BEGIN:VCARD\n"
                         "VERSION:3.0\n"
                         "    N:;Shared Location;;;\n"
                         "   FN:Shared Location\n"
                         "item1.URL;type=pref:http://maps.apple.com/?ll=%f,%f\n"
                         "item1.X-ABLabel:map url\n"
                         "END:VCARD", lat, lng];

然后将其保存到文件中,获取该文件的NSURL,并与UIActivityViewController共享,如artillery129的回答所示。

答案 5 :(得分:1)

我更新了@ naturaln0va对Swift 3的回答:
https://gist.github.com/ElegyD/510a17904917a7e7326254b824da1b2f

只需复制&粘贴到某处并按如下方式使用:

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)

答案 6 :(得分:0)

正确的方法是使用数据而非文件制作卡:

快捷键4

    import MobileCoreServices

    let locationTitle: String = ...
    let coordinate: CLLocationCoordinate2D = ...

    let vCardString = [
        "BEGIN:VCARD",
        "VERSION:4.0",
        "N:;\(locationTitle);;;",
        "FN:\(locationTitle)",
        "item1.URL;type=pref:http://maps.apple.com/?ll=\(coordinate.latitude),\(coordinate.longitude)",
        "item1.X-ABLabel:map url",
        "END:VCARD"
        ].joined(separator: "\n")

    guard let vCardData = vCardString.data(using: .utf8) else { return }

    var items = [Any]()
    let vCardActivity = NSItemProvider(item: vCardData as NSData, typeIdentifier: kUTTypeVCard as String)
    items.append(vCardActivity)
    items.append(locationTitle)
    let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil)
    present(activityViewController, animated: true, completion: nil)

答案 7 :(得分:0)

使用Swift 4.2和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
    }