Skip to content
Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!

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 GitHub stars for shinyorg/contactstore
Downloads NuGet downloads for Shiny.Contacts
Frameworks
.NET MAUI
.NET
  • Full CRUD — create, read, update, and delete device contacts
  • Fluent async queriesQuery() returns a ContactQuery builder (Where/Search/OrderBy/Skip/TakeToListAsync(ct)) with native translation on both platforms
  • Shiny permissionsGetCurrentAccess() and RequestAccess() using Shiny.Core’s AccessState model
  • 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
Platform Minimum Version
Android API 24
iOS 15.0
Changed files
  • MyApp/
Platforms/Android/AndroidManifest.xml
AndroidManifest.xml
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>
// Request access (triggers OS prompt if needed)
var access = await contactStore.RequestAccess();
if (access != AccessState.Available)
return;
// Get all contacts
var contacts = await contactStore.GetAll();
// Query with the fluent builder
var results = await contactStore.Query()
.Where(ContactField.GivenName, "John")
.OrderBy(ContactSortField.FamilyName)
.ToListAsync();
// Create a contact
var contact = new Contact { GivenName = "John", FamilyName = "Doe" };
contact.Phones.Add(new ContactPhone("555-1234", PhoneType.Mobile));
string id = await contactStore.Create(contact);
// Update
contact.GivenName = "Jane";
await contactStore.Update(contact);
// Delete
await contactStore.Delete(id);

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.

claude plugin marketplace add shinyorg/skills
claude plugin install shiny@shiny

One 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.

copilot plugin marketplace add https://github.com/shinyorg/skills
copilot plugin install shiny@shiny

One 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.

View shiny-contactstore Skill