Overview
SpamControl is a singleton class that provides functionalities for managing spam call directories, downloading databases, handling user-blocked phone numbers, scheduling background tasks, and monitoring network status. It interacts with CXCallDirectoryManager, Keychain, and NetworkMonitor to facilitate its operations. It’s available for iOS 14+⚠️ Breaking Changes and Deprecations (Version 2.0)
Deprecated Classes and Methods
The following classes and methods have been deprecated in version 2.0 and will be removed in future versions. Please migrate to the new API:Wave Class (Deprecated)
The entire Wave class and all its methods are deprecated. Use SpamControlConfiguration instead.
Deprecated:
Wave.shared- UseSpamControlConfiguration.sharedinsteadWave.shared.setup(apiKey:phoneNumber:)- UseSpamControlConfiguration.shared.setup(apiKey:phoneNumber:environment:)insteadWave.shared.setIdentificationExtension(...)- UseSpamControlConfiguration.shared.configureExtensions(with:)insteadWave.shared.setDatasetExtension(...)- UseSpamControlConfiguration.shared.configureExtensions(with:)insteadWave.shared.setUserExtension(...)- UseSpamControlConfiguration.shared.configureExtensions(with:)insteadWave.shared.getIdentificationExtension()- UseSpamControlConfiguration.shared.getBundleIdentifierExtension(with:)insteadWave.shared.getDatasetExtension()- UseSpamControlConfiguration.shared.getBundleIdentifierExtension(with:)insteadWave.shared.getUserExtension()- UseSpamControlConfiguration.shared.getBundleIdentifierExtension(with:)instead
Deprecated Methods in SpamControl
forceDownloadFullDatabase(for:)- This method is deprecated. UsedownloadFullDatabase()instead, which now handles all download scenarios automatically.
Migration Guide
See the SDK Configuration section below for the new configuration approach usingSpamControlConfiguration.
SDK Setup
TheSpamControlConfiguration class is a singleton service that manages the framework’s setup and secure key storage. It provides configuration for Call Directory extensions and securely stores the API key using the keychain.
Setting Up App Groups for Data Sharing
To enable data sharing between your main app and the Call Directory Extensions, you must configure separate App Groups for each extension type. This allows these components to access shared containers for their specific data and resources.Step 1: Enable App Groups in Xcode for the Main App
- Open your project in Xcode.
- Select your main app target in the project navigator.
- Go to the Signing & Capabilities tab.
- Click the + Capability button at the top of the screen.
- Search for and select App Groups.
- In the App Groups section, add the following group identifiers:
group.your.app.dataset(for the Dataset Extension)group.your.app.user(for the User Extension)group.your.app.identification(for the Identification Extension)
Step 2: Enable App Groups for Each Call Directory Extension
For the Dataset Extension:- Select your Dataset Call Directory Extension target.
- Go to the Signing & Capabilities tab.
- Add App Groups capability.
- Check the box for
group.your.app.dataset.
- Select your User Call Directory Extension target.
- Go to the Signing & Capabilities tab.
- Add App Groups capability.
- Check the box for
group.your.app.user.
- Select your Identification Call Directory Extension target.
- Go to the Signing & Capabilities tab.
- Add App Groups capability.
- Check the box for
group.your.app.identification.
Important: Each extension should only have access to its specific App Group to maintain proper data separation and security.
Step 3: Modify the App Group Entitlements
Ensure that the main app and Call Directory Extensions have the appropriate entitlements for using their respective App Groups.Main App Entitlements:
In the main app’s.entitlements file, add the following keys for the app groups used by each extension:
Dataset Extension Entitlements:
In the Dataset Call Directory Extension’s.entitlements file:
User Extension Entitlements:
In the User Call Directory Extension’s.entitlements file:
Identification Extension Entitlements:
In the Identification Call Directory Extension’s.entitlements file:
Step 4: Configure the SDK
The SDK configuration is divided into two distinct steps that can be performed at different moments in your app’s lifecycle:1. Extension Configuration (One-Time Setup)
Configure the Call Directory extensions usingExtensionBlockModel objects. This configuration needs to be done only once during your app’s initial setup and should be placed in your AppDelegate, @main struct, or any initialization service.
ExtensionBlockModel Structure:
Each extension is configured using an ExtensionBlockModel with the following properties:
- appGroup (String): The App Group identifier for data sharing (e.g., “group.your.app.dataset”)
- bundleIdentifier (String): The bundle identifier of the Call Directory extension target
- extensionType (ExtensionBlockModel.ExtensionType): The type of extension:
.blockSpams- Blocks calls from known spam numbers using a dataset.blockManual- Blocks calls from numbers manually added by the user.callIdentifier- Identifies incoming calls with additional information
Note: The configureExtensions(with:) method can be called multiple times, but typically should be called only once during app initialization.
2. API Credentials Setup (Required Before Database Operations)
TheSpamControlConfiguration.shared.setup(apiKey:phoneNumber:environment:) method configures your API credentials and must be called BEFORE any database download operations.
Important: Unlike the extension configuration, the setup can be called at any point in your app - even after the user logs in. You don’t need to have the phoneNumber available at app launch.
setup(apiKey:phoneNumber:environment:)
- apiKey (String): Your API key for authentication
- phoneNumber (String): The user’s phone number in international format (e.g., “5511982619489”)
- environment (SDKEnviroment): The target environment for API requests. Defaults to
.production. Use.stagefor development and testing purposes.
- ✅ After user login/authentication
- ✅ When you have both API key and phone number available
- ✅ Before calling
downloadFullDatabase()or any database operations - ✅ Can be called multiple times if credentials change (e.g., different user login)
setup() first, the SDK will:
- ❌ Fail to authenticate with the server
- ❌ Unable to download the spam phone numbers database
- ❌ Spam protection features won’t work properly
- ❌ Network requests will return authentication errors
Common Implementation Patterns
Pattern 1: Setup After User LoginConfiguration Checklist
- ✅ Extension Configuration: Can be done once at app startup (AppDelegate, @main, etc.)
- ✅ API Setup: Call
SpamControlConfiguration.shared.setup()when you have API key and phone number (can be after login) - ✅ Before Download: Always ensure
setup()was called before anydownloadFullDatabase()operations - ✅ Flexible Timing: The phone number doesn’t need to be available at app launch - setup when ready
- ✅ Environment Selection: Choose
.productionfor production or.stagefor development/testing
Important Notes
- Extension Configuration: Should be done early in the app lifecycle for proper Call Directory integration
- API Setup Flexibility: Can be called at any point when credentials become available (e.g., after user authentication)
- Database Operations: All database download/update operations require
setup()to be called first - Multiple Calls: You can call
setup()multiple times if user credentials change (e.g., different user logs in). Previous credentials are automatically cleared. - Environment Changes: If the environment changes between setup calls, all stored data is automatically cleared
- Thread Safety: The
SpamControlConfigurationclass uses a singleton pattern and is safe to call from the main thread - Error Handling: Extension configuration methods may throw errors if the configuration is invalid - handle them appropriately
Privacy Permissions Configuration
The SDK requires access to contacts to properly identify and block spam calls. You must add the appropriate privacy usage description to your app’sInfo.plist file.
Required Info.plist Configuration
Add the following key to your main app’sInfo.plist file to request contacts access permission:
Customizing the Permission Message
You should customize the usage description message to clearly explain to users why your app needs contacts access. This permission is specifically required for manual blocking functionality (User Extension) - the Dataset Extension and Identification Extension work independently without requiring contacts access. Here are some example messages you can use:Important: This permission is required specifically for the manual blocking functionality (User Extension). Without contacts access, users won’t be able to manually add or remove phone numbers from their personal block list. The Dataset Extension (spam database) and Identification Extension work independently and do not require contacts access.
Phone Number Format: The SDK only verifies and blocks phone numbers in the Brazilian format: 55 + Area Code + Phone Number (e.g., 5511987654321). Numbers in other formats will not be processed by the spam blocking system.
Extension Management
The SDK now supports three separate Call Directory extensions for comprehensive spam protection:- Dataset Extension: Handles blocking numbers from the spam database
- User Extension: Handles numbers manually blocked by the user
- Identification Extension: Handles caller ID and spam identification
Retrieving Configured Extensions
SDK’s usage
TheSpamControl class provides functionality for managing call blocking, identifying spam calls, downloading datasets, and interacting with background tasks. It utilizes the Call Directory framework and other internal services to manage these tasks. Below is a breakdown of its key methods and properties.
Overview
- Singleton: The class is implemented as a singleton, accessible via
SpamControl.shared. - App Group Integration: The class leverages an app group for sharing data between the main app and its extension.
- Network Monitoring: Monitors network connection and cellular data preferences for downloading datasets.
- Call Directory Integration: Interacts with the Call Directory API to manage blocking and identifying phone numbers.
- Background Task Management: Supports background tasks for updating call blocking data asynchronously.
Key Properties
downloadWithCellularDataEnabled
- Type:
Bool - Description: A flag that determines whether cellular data can be used for downloading datasets. Defaults to
false.
isNetworkConnected
- Type:
Bool - Description: Returns whether the device is connected to the internet.
isOnWiFi
- Type:
Bool - Description: Returns whether the device is connected to a Wi-Fi network.
Key Methods
openSettings()
- Availability: iOS 13.4 and later
- Description: Opens the settings for the Call Directory extension.
- Usage:
isCallDatasetDirectoryEnabled()
- Returns:
Bool - Description: Checks whether the call dataset directory is enabled.
- Usage:
isCallUserDirectoryEnabled()
- Returns:
Bool - Description: Checks whether the user call directory is enabled.
- Usage:
isCallIdentificationDirectoryEnabled()
- Returns:
Bool - Description: Checks whether the identification call directory is enabled.
- Usage:
areAllExtensionsEnabled()
- Returns:
Bool - Description: Checks whether all three call directory extensions are enabled.
- Usage:
downloadFullDatabase()
- Description: Downloads and prepares the spam phone number database for use. This method only downloads if 24 hours have passed since the last download.
- Usage:
forceDownloadFullDatabase(for phoneNumber: String)
- Description: ⚠️ Deprecated in version 2.0. This method is deprecated. Use
downloadFullDatabase()instead, which now handles all download scenarios automatically. - Parameters:
phoneNumber: The phone number used to fetch and register the database
- Usage:
applySpamPhoneNumberBlocking()
- Description: Applies the current spam phone number list to the CallKit extension.
- Usage:
applyIdentificationSpamPhoneNumberBlocking()
- Description: Applies the spam phone number identification settings to the CallKit extension.
- Usage:
downloadSpamCategories(cacheValidityDuration: TimeInterval = 3600)
- Returns:
[SpamCategory] - Description: Downloads all available spam categories associated with the authenticated phone number. This method retrieves categories from cache if available and not expired. Otherwise, it fetches fresh data from the remote service.
- Parameters:
cacheValidityDuration: Maximum age of cached categories in seconds (default: 3600 seconds / 1 hour)
- Usage:
toggleCategoryBlockState(categoryId: Int)
- Returns:
[SpamCategory] - Description: Toggles the block state for a specific category and returns the complete list of categories with updated states.
- Usage:
blockSpamPhoneNumberByCategories(for categoriesIds: [NSNumber])
- Description: Blocks spam phone numbers based on selected category identifiers. This method stores the selected category IDs in persistent storage and reloads the Call Directory extension.
- Parameters:
categoriesIds: An array of category identifiers to block
- Usage:
totalBlockedCalls()
- Returns:
TotalBlockedCalls? - Description: Fetches the total number of blocked calls from the remote service.
- Usage:
totalPhoneNumbersAtDatabase()
- Returns:
Int? - Description: Returns the total count of phone entries stored in the database.
- Usage:
blockUserPhoneNumbers(_ phoneNumbers: [String])
- Description: Blocks a list of phone numbers (as String) and updates the call directory.
- Parameters:
phoneNumbers: An array of phone numbers to block
- Returns:
[Int64] - Throws: An error if any phone number format is invalid, already blocked, or if the Call Directory is not enabled
- Usage:
blockUserPhoneNumber(phoneNumber: String)
- Description: Blocks a user-provided phone number (as a String) and updates the call directory.
- Parameters:
phoneNumber: The phone number to block
- Returns:
[Int64] - Throws: An error if the phone number format is invalid, already blocked, or if the Call Directory is not enabled
- Usage:
retrievedBlockedUserPhoneNumbers()
- Returns:
[CXCallDirectoryPhoneNumber] - Description: Retrieves the list of blocked user phone numbers.
- Usage:
unblockPhoneNumber(phoneNumber: String)
- Description: Unblocks a specific phone number.
- Parameters:
phoneNumber: The phone number to unblock
- Throws: An error if the unblock operation fails
- Usage:
Create a Call Directory Extension
This document provides a step-by-step guide on how to create and configure a Call Directory Extension for your app to block or identify incoming calls on iOS devices. The Call Directory Extension provides the functionality of blocking and identifying phone numbers without interfering with the user’s normal phone usage.Step 1: Create New Call Directory Extensions
The SDK requires three separate Call Directory Extensions to provide comprehensive spam protection:- Dataset Directory Extension: Handles blocking numbers from the spam database
- User Directory Extension: Handles numbers manually blocked by the user
- Identification Directory Extension: Handles caller ID and spam identification
- Open your project in Xcode.
- Add a New Target:
- Go to File > New > Target.
- Under iOS, select Call Directory Extension and click Next.
- Provide a name for your extension (e.g.,
SpamControlDatasetDirectory) and select the app you want to associate the extension with. - Click Finish.
- Add another New Target:
- Go to File > New > Target.
- Under iOS, select Call Directory Extension and click Next.
- Provide a name for your extension (e.g.,
SpamControlUserDirectory) and select the app you want to associate the extension with. - Click Finish.
- Add a third New Target:
- Go to File > New > Target.
- Under iOS, select Call Directory Extension and click Next.
- Provide a name for your extension (e.g.,
SpamControlIdentificationDirectory) and select the app you want to associate the extension with. - Click Finish.
Step 2: Configure the Call Directory Extensions
Modify the Dataset Directory Extension CallDirectoryHandler.swift
In the CallDirectoryHandler.swift file, you will use the WaveCallDatasetDirectoryHandler to manage the phone numbers for blocking and identification. This approach ensures a streamlined integration with your existing FeatureSpamControl logic.
Understanding the hintIdentifier Parameter
The WaveCallUserDirectoryHandler and WaveCallIdentificationHandler accept an optional hintIdentifier parameter during initialization. This parameter defines the label text that appears on the user’s screen when an incoming call is identified.
Purpose:
- User Experience: Provides clear context to users about why a call is being flagged
- Customization: Allows you to set a custom identification label in your preferred language
- Caller ID Display: The hint appears directly on the incoming call screen
- For User Directory: “Blocked”, “Blocked by Me”, “Número Bloqueado”
- For Identification: “Spam”, “Spam Likely”, “Possível Spam”, “Telemarketing”
Adding FeatureSpamControl as a Dependency to the Call Directory Extension
To integrate the FeatureSpamControl framework into your Call Directory Extension, follow these steps. This will allow the extension to leverage the features and functionality provided by FeatureSpamControl, without embedding the framework directly into the extension.
Step 1: Add FeatureSpamControl as a Dependency in Your Call Directory Extension
- Open your Xcode project.
- Select the Call Directory Extension target from the project navigator.
- Go to the General tab.
- In the Frameworks, Libraries, and Embedded Content section, click the + button.
- Search for
FeatureSpamControland add it to the list of dependencies.
Step 2: Set FeatureSpamControl to Not Be Embedded
To prevent FeatureSpamControl from being embedded into the extension’s bundle (which is the default behavior when adding a framework), you need to set it to Do Not Embed.
- After adding
FeatureSpamControlas a dependency, locate the Embedded Content column in the Frameworks, Libraries, and Embedded Content section. - Change the setting for
FeatureSpamControlto Do Not Embed. This ensures that the framework is linked, but not included in the extension bundle, as it will be shared through the App Group.
Note: This is important to ensure that the framework is not duplicated inside the extension’s bundle, reducing app size and avoiding conflicts.
Step 3: Verify FeatureSpamControl is Linked Correctly
Ensure that the framework is properly linked and accessible by the extension:
- Go to the Build Phases tab of your Call Directory Extension target.
- Under Link Binary With Libraries, confirm that
FeatureSpamControlis listed. This confirms that the framework is correctly linked and accessible to the extension during runtime.
Step 4: Use FeatureSpamControl in the Call Directory Extension
Once the framework is added as a dependency (without embedding), you can begin using it within the extension using the appropriate handlers as shown in the examples above.
User Phone Number Management
The SDK provides comprehensive functionality for managing user-blocked phone numbers separately from the spam database.Blocking User Phone Numbers
Retrieving Blocked User Phone Numbers
Unblocking a Specific Phone Number
Spam Categories Management
The SDK now supports category-based spam filtering, allowing users to select which types of spam calls they want to block.Downloading Available Categories
Toggling Category Block State
Blocking by Categories
Statistics and Analytics
Total Blocked Calls
Database Statistics
Network Management
The SDK includes network monitoring capabilities to optimize data usage:Key Properties
isNetworkConnected: Returns whether the device is connected to the internetisOnWiFi: Returns whether the device is connected to a Wi-Fi networkdownloadWithCellularDataEnabled: A flag that determines whether cellular data can be used for downloading datasets (defaults tofalse)
Usage Example
Enabling Call Blocking & Identification in the Phone App
After building and running your app and Call Directory Extension, the next step is to enable the Call Blocking & Identification feature in the Phone app on the device. This allows your extension to block or identify phone calls based on the numbers you’ve provided in your code.Step 1: Install and Run the App
- Build and run the app and extension on a physical iOS device.
- Ensure that the app and extension are properly installed on the device.
- The app should be visible on the home screen, and the Call Directory Extension should be available for configuration in the Settings app.
Step 2: Open the Settings App
- On the device, open the Settings app.
- Scroll down and tap Phone.
Step 3: Enable the Call Blocking & Identification Toggle
- In the Phone settings, find and tap on Call Blocking & Identification.
- You will see a list of all the Call Directory Extensions installed on your device.
- Find your app’s Call Directory Extension in the list (it will display the name you set for the extension).
-
Enable the toggle next to your extension to turn on Call Blocking & Identification.
- This will allow your extension to start identifying and blocking calls based on the phone numbers you’ve configured in your extension.
Step 4: Verify Call Blocking and Identification
Once the toggle is enabled, you can verify that the feature works as expected:- Test Blocking: Try receiving a call from a number you’ve added to the blocked numbers list in your extension’s code. The call should be blocked.
- Test Identification: Try receiving a call from a number you’ve added to the identified numbers list in your extension’s code. The caller ID should be updated to reflect the label you’ve set for the number (e.g., “Spam Caller”).
Note: Changes in the Call Directory Extension may take a few moments to take effect. If you don’t see immediate results, try toggling the switch off and back on.
Troubleshooting
- Call Directory Extensions Not Appearing: If your extensions do not appear in the Call Blocking & Identification list, ensure that both extensions are properly installed and that you’ve correctly followed the setup steps for each one.
- Extensions Not Working: If the extensions are enabled but calls are not being blocked or identified, check that:
- Numbers are correctly added to the respective extensions (spam database vs. user-blocked numbers)
- Both extensions have the correct entitlements and permissions
- App Groups are properly configured for data sharing
- The extensions are using the correct bundle identifiers and app group identifiers
- Partial Functionality: If only one type of blocking works (either spam database or user-blocked), verify that both extensions are enabled in Settings and have proper app group access.
SDK estimated size
The size variations depend on the specific features and resources included in the SDK, such as call management logic, UI components, and any other integrations.- 3 MB to 7 MB: SDK with basic functionality, including an entry point and methods for blocking and managing calls. This version does not include a user interface (UI).
- 10 MB to 15 MB: SDK with full functionality, including an entry point, methods for blocking and managing calls, and a user interface (UI) built using SwiftUI.