Contact Store | Getting Started
A cross-platform library for accessing device contacts on Android and iOS. Provides full CRUD operations, a fluent async query builder, Shiny’s AccessState permission model, and dependency injection integration. Built on Shiny.Core, so it runs in any Shiny host — with or without .NET MAUI.
| GitHub | |
| Downloads |
Features
Section titled “Features”- Full CRUD — create, read, update, and delete device contacts
- Fluent async queries —
Query()returns aContactQuerybuilder (Where/Search/OrderBy/Skip/Take→ToListAsync(ct)) with native translation on both platforms - Shiny permissions —
GetCurrentAccess()andRequestAccess()using Shiny.Core’sAccessStatemodel - No MAUI required — built on
Shiny.Core, so it works in any Shiny host - AOT compatible — trimmer and AOT safe
- Dependency injection — register with a single
AddContactStore()call
Platforms
Section titled “Platforms”| Platform | Minimum Version |
|---|---|
| Android | API 24 |
| iOS | 15.0 |
- MyApp/
1<?xml version="1.0" encoding="utf-8"?>2<manifest xmlns:android="http://schemas.android.com/apk/res/android">3 <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true">4 </application>5 <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>6 <uses-permission android:name="android.permission.BATTERY_STATS" />7 <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />8 <uses-permission android:name="android.permission.INTERNET" />9 <uses-permission android:name="android.permission.READ_CONTACTS" />10 <uses-permission android:name="android.permission.WRITE_CONTACTS" />11</manifest>Quick Example
Section titled “Quick Example”// Request access (triggers OS prompt if needed)var access = await contactStore.RequestAccess();if (access != AccessState.Available) return;
// Get all contactsvar contacts = await contactStore.GetAll();
// Query with the fluent buildervar results = await contactStore.Query() .Where(ContactField.GivenName, "John") .OrderBy(ContactSortField.FamilyName) .ToListAsync();
// Create a contactvar contact = new Contact { GivenName = "John", FamilyName = "Doe" };contact.Phones.Add(new ContactPhone("555-1234", PhoneType.Mobile));string id = await contactStore.Create(contact);
// Updatecontact.GivenName = "Jane";await contactStore.Update(contact);
// Deleteawait contactStore.Delete(id);Photos vs Thumbnails
Section titled “Photos vs Thumbnails”Bulk reads — GetAll() and Query() — populate only the lightweight Thumbnail. The full-resolution Photo is null on these results: decoding every contact’s full image into memory at once spikes memory and can get the app OOM/jetsam-killed on a real device with many photo contacts. Fetch a single contact with GetById(id) to get the full Photo (it also includes the Thumbnail).
Bind list rows to Thumbnail, and load Photo on a per-contact detail screen.
AI Coding Assistant
Section titled “AI Coding Assistant”Step 1 — Add the marketplace:
claude plugin marketplace add shinyorg/skillsStep 2 — Install the plugin:
claude plugin install shiny@shinyOne plugin installs all 35 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.
Step 1 — Add the marketplace:
copilot plugin marketplace add https://github.com/shinyorg/skillsStep 2 — Install the plugin:
copilot plugin install shiny@shinyOne plugin installs all 35 Shiny skills. Your agent loads only the skill relevant to what you're building, so there's no cost to having them all available.
Next Steps
Section titled “Next Steps”- Permissions — Shiny
AccessStatepermission handling - Querying — the fluent query builder and what translates natively
- Release Notes — Version history


