A Kotlin Multiplatform library to fetch user contacts from Android and iOS with a Compose-friendly API. Provides names, initials, phone numbers, and avatars, with minimal setup.
- Fetch contacts on Android (requires context) and iOS (no context required).
- Provides
Contactdata class with:displayNameinitialsphoneNumbersavatar(URIorImageBitmap)
- Compose-ready: use
rememberContactsProvider()directly in your composable screen. - Works seamlessly in Kotlin Multiplatform projects.
- Minimal setup : — no need to configure entry points manually. — ready to be injected via Dependency Injection Framework Koin.
dependencies {
implementation("io.github.dev-bilal-azzam:kontacts:$latest_version")
}- Introduced custom field selection when fetching contacts.
- Users can now specify exactly which fields they need:
- Phone numbers
- Names (first - last)
- Avatar
- This avoids unnecessary queries and improves performance when only a subset of data is required.
contactsProvider.getAllContacts(
fields = setOf(ContactField.ID, ContactField.FIRST_NAME)
)- Optimized how phone numbers are fetched
- Results:
- Before: ~10 seconds for large contact lists with phone numbers.
- After: ~200 ms (same speed as fetching names only).
- Faster: Large contact lists now load up to 50× faster when phone numbers are included.
- Flexible: Apps can now fetch only the fields they actually need.
@Composable
fun ContactsScreen() {
val contactsProvider = rememberContactsProvider()
var contacts by remember { mutableStateOf<List<Contact>>(emptyList()) }
LaunchedEffect(Unit) {
// Ensure permission is granted
contacts = contactsProvider.getAllContacts(
fields = setOf(
ContactField.ID,
ContactField.FIRST_NAME,
ContactField.PHONE_NUMBERS
)
)
}
LazyColumn {
items(contacts) { contact ->
Text(text = contact.displayName)
}
}
}
// Common
import com.bilalazzam.contacts_provider.ContactsProvider
import org.koin.core.scope.Scope
// create an expect function to create ContactsProvider
expect fun Scope.createContactsProvider(): ContactsProviderthen create the actual implementation for each platform
// Android
import com.bilalazzam.contacts_provider.ContactsProviderFactory
actual fun Scope.createContactsProvider(): ContactsProvider {
return ContactsProviderFactory(this.get()).createContactsProvider()
}
// Ios
actual fun Scope.createContactsProvider(): ContactsProvider {
return ContactsProviderFactory().createContactsProvider()
}then in koin module
import org.koin.dsl.module
val dataProviderModule = module {
single { createContactsProvider() }
}the just inject it to your Repository or Datasource
class ContactsRepositoryImpl(
private val contactsProvider: ContactsProvider
) : ContactsRepository {
private suspend fun getDeviceContacts(): List<DeviceContact> {
return contactsProvider.getAllContacts(
fields = setOf(ID, FIRST_NAME, LAST_NAME, PHONE_NUMBERS)
)
}
}<uses-permission android:name="android.permission.READ_CONTACTS" /><key>NSContactsUsageDescription</key>
<string>We need access to your contacts to display them in the app.</string>This project is licensed under the MIT License.
See the LICENSE file for details.