As I said on twitter WP8 doesn't allow to launch the contact details either from a customized launcher task or via an app2app custom protocol.

The people hub does support importing vCards in a screen very similar to the contact details screen. You can use this feature primarily to import vCards or optionally to show contact details (even though it'll show up as a new contact). Here's the vCard app2app file association for the people hub:

<Extensions> <FileTypeAssociation Name="VCard" Category="phone.fileTypeAssociation" TaskID="ViewVCardContact" NavUriFragment="VCardMode=2&vCardFileToken=%s"> <Logos> <Logo Size="small" IsResource="true">res://ContactsRes{ScreenResolution}!VCard.FileTypeIcon.Small.png</Logo> <Logo Size="medium" IsResource="true">res://ContactsRes{ScreenResolution}!VCard.FileTypeIcon.Medium.png</Logo> <Logo Size="large" IsResource="true">res://ContactsRes{ScreenResolution}!VCard.FileTypeIcon.Large.png</Logo> </Logos> <SupportedFileTypes> <FileType ContentType="text/vcard">.vcf</FileType> <FileType ContentType="text/x-vcard">.vcf</FileType> </SupportedFileTypes> </FileTypeAssociation> </Extensions>

In order to use this app2app custom protocol we can write up some code that creates a vCard VCF file, saves it to IsoStore and launches the vCard in the people hub.

private void MainPage_Loaded(object sender, RoutedEventArgs e) { var contacts = new Contacts(); contacts.SearchCompleted += contacts_SearchCompleted; contacts.SearchAsync(string.Empty, FilterKind.None, null); } private async void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e) { // get a Contact and build a vCard for it Contact contact = e.Results.First(); string vcard = GetContactVCard(contact); Debug.WriteLine(vcard); // write the vCard to IsoStore as a VCF file using (var s = IsolatedStorageFile.GetUserStoreForApplication().CreateFile("myContact.vcf")) using (var sw = new StreamWriter(s)) { sw.Write(vcard); } // launch the VCF file var vcardStorageFile = await ApplicationData.Current.LocalFolder.GetFileAsync("myContact.vcf"); Launcher.LaunchFileAsync(vcardStorageFile); }

Next we'll have to implement the function that builds a vCard. We'll use a vCard version 3.0 since we need Base64 embedded images (more on that later). I copied the vCard 3.0 format from Wikipedia so this example doesn't have any of the Microsoft specific extensions. I just copied the vCard into the code and poured in some data from the Contact class.

private string GetContactVCard(Contact contact) { return string.Format(@"BEGIN:VCARD VERSION:3.0 N:{0};{1} FN:{2} ORG:{3} TITLE:{4} PHOTO;TYPE=PNG;ENCODING=B:{9} TEL;TYPE=WORK,VOICE:{5} TEL;TYPE=HOME,VOICE:{6} ADR;TYPE=WORK:;;{10} ADR;TYPE=HOME:;;{11} EMAIL;TYPE=PREF,INTERNET:{7} REV:{8} END:VCARD", contact.CompleteName.LastName, contact.CompleteName.FirstName, contact.DisplayName, contact.Companies.Any() ? contact.Companies.First().CompanyName : string.Empty, contact.CompleteName.Title, contact.PhoneNumbers.Any(p => p.Kind == PhoneNumberKind.Work) ? contact.PhoneNumbers.First(p => p.Kind == PhoneNumberKind.Work).PhoneNumber : string.Empty, contact.PhoneNumbers.Any(p => p.Kind != PhoneNumberKind.Work) ? contact.PhoneNumbers.First(p => p.Kind != PhoneNumberKind.Work).PhoneNumber : string.Empty, contact.EmailAddresses.Any() ? contact.EmailAddresses.First().EmailAddress : string.Empty, DateTime.Now.ToFileTimeUtc(), GetPhotoBase64(contact), contact.Addresses.Any(a => a.Kind == AddressKind.Home) ? BuildAddress(contact.Addresses.First(a => a.Kind == AddressKind.Home).PhysicalAddress) : string.Empty, contact.Addresses.Any(a => a.Kind == AddressKind.Work) ? BuildAddress(contact.Addresses.First(a => a.Kind == AddressKind.Work).PhysicalAddress) : string.Empty ); }

You can see that I didn't spend too much time perfecting this logic. It might be best if you added some edge condition handling and maybe move to a StringBuilder. Next we'll build the somewhat more complex address string:

private string BuildAddress(CivicAddress physicalAddress) { StringBuilder sb = new StringBuilder(); string[] address = new string[] { physicalAddress.AddressLine1, physicalAddress.AddressLine2, physicalAddress.City + " " + physicalAddress.StateProvince, physicalAddress.CountryRegion, physicalAddress.PostalCode }; foreach (var line in address) if (!string.IsNullOrEmpty(line)) sb.Append(line + ";"); return sb.ToString(); }

And finally we'll need to embed images as part of our vCard. We're embedding contact photos in base64 since WP8 doesn't have a URL we can use for that contact's photo.

private string GetPhotoBase64(Contact contact) { using (var picture = contact.GetPicture()) { if (picture == null) { return null; } else { using (var sr = new StreamReader(picture)) { byte[] data = new byte[picture.Length]; picture.Read(data, 0, data.Length); return Convert.ToBase64String(data); } } } }

When we run this code snippet we can see it carries over most of the details of a Contact's properties into the exported/imported vCard: