Commit 7a905f79 authored by Wei Han's avatar Wei Han Committed by alep

outgoing call bug fixed

parent f67df9f1
import React, { useEffect, useState, useCallback } from 'react';
import { View, Text, Button, StyleSheet, Alert, Linking, Platform, NativeModules } from 'react-native';
import { check, request, PERMISSIONS, RESULTS } from 'react-native-permissions';
import AsyncStorage from '@react-native-async-storage/async-storage';
// import AsyncStorage from '@react-native-async-storage/async-storage';
import DeviceInfo from 'react-native-device-info';
const permissionsList = [
{ key: 'READ_PHONE_STATE', android: PERMISSIONS.ANDROID.READ_PHONE_STATE },
{ key: 'READ_CALL_LOG', android: PERMISSIONS.ANDROID.READ_CALL_LOG },
{ key: 'Display Over Other Apps', android: null }, // overlay special case
];
async function saveVIPNumber(name: string, number: string) {
try {
await AsyncStorage.setItem('vipName', name);
await AsyncStorage.setItem('vipNumber', number);
const {VIPStorage} = NativeModules;
if (!VIPStorage) {
console.error("❌ VIPStorage is undefined. Did you register StoragePackage in MainApplication?");
return;
const permissionsList = Platform.select({
android: [
{ key: 'READ_PHONE_STATE', android: PERMISSIONS.ANDROID.READ_PHONE_STATE },
{ key: 'READ_CALL_LOG', android: PERMISSIONS.ANDROID.READ_CALL_LOG },
{ key: 'Display Over Other Apps', android: null }, // overlay special case
],
ios: [{ key: 'Call Directory Extension', ios: true }],
})!;
const { OverlayPermission } = NativeModules;
type CallDirectoryManagerType = {
getEnabledStatusForExtension(identifier: string): Promise<number>;
reloadExtension(identifier: string): Promise<boolean>;
};
const CallDirectoryManager: CallDirectoryManagerType | undefined = NativeModules.CallDirectoryManager;
// async function saveVIPNumber(name: string, number: string) {
// try {
// await AsyncStorage.setItem('vipName', name);
// await AsyncStorage.setItem('vipNumber', number);
// const {VIPStorage} = NativeModules;
// if (!VIPStorage) {
// console.error("❌ VIPStorage is undefined. Did you register StoragePackage in MainApplication?");
// return;
// }
// await VIPStorage.saveVIP(name, number);
// console.log('VIPStorage from NativeModules:', NativeModules.VIPStorage);
// } catch (error) {
// console.error('Failed to save VIP info:', error);
// }
// }
async function checkOverlayPermission() {
if (Platform.OS === 'android') {
try {
const granted: boolean = await OverlayPermission.hasPermission();
if (!granted) {
Alert.alert(
'Overlay Permission Required',
'This app needs permission to display over other apps.',
[{ text: 'Open Settings', onPress: openOverlaySettings }]
);
}
return granted;
} catch (e) {
console.error('Error checking overlay permission:', e);
return false;
}
await VIPStorage.saveVIP(name, number);
console.log('VIPStorage from NativeModules:', NativeModules.VIPStorage);
} catch (error) {
console.error('Failed to save VIP info:', error);
} else {
return true; // iOS doesn't require this
}
}
const openOverlaySettings = async () => {
if (Platform.OS === 'android') {
const pkg = DeviceInfo.getBundleId(); // gets your app package name
try {
await Linking.openSettings(); // fallback
await Linking.openURL(`package:${pkg}`);
} catch (err) {
console.warn('Failed to open overlay settings:', err);
}
}
};
export default function App() {
const [statuses, setStatuses] = useState<Record<string, string>>({});
const checkAllPermissions = useCallback(async () => {
const newStatuses: Record<string, string> = {};
if (Platform.OS === 'ios') {
try {
if (CallDirectoryManager) {
const status = await CallDirectoryManager.getEnabledStatusForExtension(
"com.whoscall.app.CallDirectoryExtension"
);
newStatuses['Call Directory Extension'] = status === 2 ? RESULTS.GRANTED : RESULTS.DENIED;
} else {
console.warn("⚠️ CallDirectoryManager native module not available");
newStatuses['Call Directory Extension'] = RESULTS.DENIED;
}
} catch (e) {
console.error("Error checking Call Directory extension:", e);
newStatuses['Call Directory Extension'] = RESULTS.DENIED;
}
} else {
for (const perm of permissionsList) {
if (perm.key === 'Display Over Other Apps') {
// Overlay not checkable in RN
newStatuses[perm.key] = RESULTS.DENIED;
const granted = await checkOverlayPermission();
newStatuses[perm.key] = granted ? RESULTS.GRANTED : RESULTS.DENIED;
continue;
}
const result = await check(perm.android!);
newStatuses[perm.key] = result;
if ('android' in perm && perm.android) {
const result = await check(perm.android);
newStatuses[perm.key] = result;
}
}
setStatuses(newStatuses);
......@@ -53,43 +114,37 @@ export default function App() {
'This app needs permission to display over other apps.',
[{ text: 'Open Settings', onPress: openOverlaySettings }]
);
} else {
const result = await request(perm.android!);
} else if ('android' in perm && perm.android) {
const result = await request(perm.android);
setStatuses(prev => ({ ...prev, [perm.key]: result }));
}
}
if (Platform.OS as string === 'ios') {
Alert.alert(
"Enable Caller ID",
"Go to Settings → Phone → Call Blocking & Identification and enable [Your App] to see caller ID labels."
);
}
}
},[]);
}
}, []);
useEffect(() => {
console.log("PermissionsScreen mounted");
console.log("All NativeModules keys:", Object.keys(NativeModules));
console.log("VIPStorage:", NativeModules.VIPStorage);
// console.log("VIPStorage:", NativeModules.VIPStorage);
saveVIPNumber('VIP User', '+60123456789');
// saveVIPNumber('VIP User', '+60123456789');
checkAllPermissions();
},[checkAllPermissions]);
// Open Overlay Settings
const openOverlaySettings = async () => {
if (Platform.OS === 'android') {
const pkg = DeviceInfo.getBundleId(); // gets your app package name
const url = `package:${pkg}`;
try {
await Linking.openSettings(); // fallback
await Linking.openURL(`android.settings.action.MANAGE_OVERLAY_PERMISSION/${url}`);
} catch (err) {
console.warn('Failed to open overlay settings:', err);
}
}
};
const allGranted = Object.values(statuses).every(s => s === RESULTS.GRANTED);
return (
<View style={styles.container}>
<Text style={styles.title}>Permissions Status</Text>
{permissionsList.map(perm => (
{(permissionsList ?? []).map(perm => (
<View key={perm.key} style={styles.row}>
<Text style={styles.text}>{perm.key}</Text>
<Text
......
......@@ -13,10 +13,16 @@ import android.content.SharedPreferences
class IncomingCallService : CallScreeningService() {
override fun onScreenCall(callDetails: Details) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (callDetails.callDirection != Details.DIRECTION_INCOMING) {
// Not an incoming call, ignore
return
}
}
val number = callDetails.handle?.schemeSpecificPart ?: "Unknown"
// Lookup VIPs
val prefs = getSharedPreferences("WhoscallPrefs", MODE_PRIVATE)
// val prefs = getSharedPreferences("WhoscallPrefs", MODE_PRIVATE)
val vipNumber = "+60108222562"
val vipName = "Arvin"
......
......@@ -19,7 +19,7 @@ class MainApplication : Application(), ReactApplication {
// Packages that cannot be autolinked yet can be added manually here, for example:
// add(MyReactNativePackage())
add(StoragePackage())
add(MyAppPackage())
}
override fun getJSMainModuleName(): String = "index"
......
// MyAppPackage.kt
package com.whoscall
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager
class MyAppPackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return listOf(OverlayPermissionModule(reactContext))
}
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return emptyList()
}
}
// OverlayPermissionModule.kt
package com.whoscall
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReactContextBaseJavaModule
import com.facebook.react.bridge.ReactMethod
import com.facebook.react.bridge.Promise
import android.os.Build
import android.provider.Settings
class OverlayPermissionModule(reactContext: ReactApplicationContext) :
ReactContextBaseJavaModule(reactContext) {
override fun getName(): String {
return "OverlayPermission"
}
@ReactMethod
fun hasPermission(promise: Promise) {
val canDraw = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
Settings.canDrawOverlays(reactApplicationContext)
} else {
true
}
promise.resolve(canDraw)
}
}
......@@ -32,10 +32,4 @@ target 'whoscall' do
# :ccache_enabled => true
)
end
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-Contacts', :path => "#{permissions_path}/Contacts.podspec"
pod 'Permission-Phone', :path => "#{permissions_path}/Phone.podspec"
pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications.podspec"
end
......@@ -2645,7 +2645,7 @@ SPEC CHECKSUMS:
fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd
glog: 5683914934d5b6e4240e497e0f4a3b42d1854183
hermes-engine: 4f8246b1f6d79f625e0d99472d1f3a71da4d28ca
RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f
RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669
RCTDeprecation: c4b9e2fd0ab200e3af72b013ed6113187c607077
RCTRequired: e97dd5dafc1db8094e63bc5031e0371f092ae92a
RCTTypeSafety: 720403058b7c1380c6a3ae5706981d6362962c89
......
......@@ -3,48 +3,22 @@
archiveVersion = 1;
classes = {
};
objectVersion = 70;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
0C80B921A6F3F58F76C31292 /* libPods-whoscall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-whoscall.a */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
2F60E0202E66CCEF00C504BE /* whoscallDirectoryExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 2F60E0192E66CCEF00C504BE /* whoscallDirectoryExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
3C68549A1AFF3687BD1D58DA /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
761780ED2CA45674006654EE /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 761780EC2CA45674006654EE /* AppDelegate.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
A3AA3DDDD267D1DE50433D9E /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
2F60E01E2E66CCEF00C504BE /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 2F60E0182E66CCEF00C504BE;
remoteInfo = whoscallDirectoryExtension;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
2F60E0212E66CCEF00C504BE /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
2F60E0202E66CCEF00C504BE /* whoscallDirectoryExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
13B07F961A680F5B00A75B9A /* whoscall.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = whoscall.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = whoscall/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = whoscall/Info.plist; sourceTree = "<group>"; };
13B07FB81A68108700A75B9A /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = PrivacyInfo.xcprivacy; path = whoscall/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
2F60E0192E66CCEF00C504BE /* whoscallDirectoryExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = whoscallDirectoryExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
3B4392A12AC88292D35C810B /* Pods-whoscall.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-whoscall.debug.xcconfig"; path = "Target Support Files/Pods-whoscall/Pods-whoscall.debug.xcconfig"; sourceTree = "<group>"; };
5709B34CF0A7D63546082F79 /* Pods-whoscall.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-whoscall.release.xcconfig"; path = "Target Support Files/Pods-whoscall/Pods-whoscall.release.xcconfig"; sourceTree = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-whoscall.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-whoscall.a"; sourceTree = BUILT_PRODUCTS_DIR; };
......@@ -53,20 +27,6 @@
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
2F60E0242E66CCEF00C504BE /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = 2F60E0182E66CCEF00C504BE /* whoscallDirectoryExtension */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
2F60E01A2E66CCEF00C504BE /* whoscallDirectoryExtension */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (2F60E0242E66CCEF00C504BE /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = whoscallDirectoryExtension; sourceTree = "<group>"; };
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
......@@ -76,13 +36,6 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
2F60E0162E66CCEF00C504BE /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
......@@ -119,7 +72,6 @@
children = (
13B07FAE1A68108700A75B9A /* whoscall */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
2F60E01A2E66CCEF00C504BE /* whoscallDirectoryExtension */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
BBD78D7AC51CEA395F1C20DB /* Pods */,
......@@ -133,7 +85,6 @@
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* whoscall.app */,
2F60E0192E66CCEF00C504BE /* whoscallDirectoryExtension.appex */,
);
name = Products;
sourceTree = "<group>";
......@@ -161,55 +112,27 @@
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
2F60E0212E66CCEF00C504BE /* Embed Foundation Extensions */,
);
buildRules = (
);
dependencies = (
2F60E01F2E66CCEF00C504BE /* PBXTargetDependency */,
);
name = whoscall;
productName = whoscall;
productReference = 13B07F961A680F5B00A75B9A /* whoscall.app */;
productType = "com.apple.product-type.application";
};
2F60E0182E66CCEF00C504BE /* whoscallDirectoryExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 2F60E0252E66CCEF00C504BE /* Build configuration list for PBXNativeTarget "whoscallDirectoryExtension" */;
buildPhases = (
2F60E0152E66CCEF00C504BE /* Sources */,
2F60E0162E66CCEF00C504BE /* Frameworks */,
2F60E0172E66CCEF00C504BE /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
2F60E01A2E66CCEF00C504BE /* whoscallDirectoryExtension */,
);
name = whoscallDirectoryExtension;
packageProductDependencies = (
);
productName = whoscallDirectoryExtension;
productReference = 2F60E0192E66CCEF00C504BE /* whoscallDirectoryExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1640;
LastUpgradeCheck = 1210;
TargetAttributes = {
13B07F861A680F5B00A75B9A = {
LastSwiftMigration = 1120;
};
2F60E0182E66CCEF00C504BE = {
CreatedOnToolsVersion = 16.4;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "whoscall" */;
......@@ -226,7 +149,6 @@
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* whoscall */,
2F60E0182E66CCEF00C504BE /* whoscallDirectoryExtension */,
);
};
/* End PBXProject section */
......@@ -238,14 +160,7 @@
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
3C68549A1AFF3687BD1D58DA /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
2F60E0172E66CCEF00C504BE /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
A3AA3DDDD267D1DE50433D9E /* PrivacyInfo.xcprivacy in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......@@ -276,14 +191,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-whoscall/Pods-whoscall-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-whoscall/Pods-whoscall-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-whoscall/Pods-whoscall-frameworks.sh\"\n";
......@@ -319,14 +230,10 @@
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-whoscall/Pods-whoscall-resources-${CONFIGURATION}-input-files.xcfilelist",
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-whoscall/Pods-whoscall-resources-${CONFIGURATION}-output-files.xcfilelist",
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-whoscall/Pods-whoscall-resources.sh\"\n";
......@@ -343,23 +250,8 @@
);
runOnlyForDeploymentPostprocessing = 0;
};
2F60E0152E66CCEF00C504BE /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
2F60E01F2E66CCEF00C504BE /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 2F60E0182E66CCEF00C504BE /* whoscallDirectoryExtension */;
targetProxy = 2F60E01E2E66CCEF00C504BE /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
......@@ -415,87 +307,6 @@
};
name = Release;
};
2F60E0222E66CCEF00C504BE /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = whoscallDirectoryExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = whoscallDirectoryExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.example.whoscall.whoscallDirectoryExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
2F60E0232E66CCEF00C504BE /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ARCHS = "$(ARCHS_STANDARD_64_BIT)";
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = whoscallDirectoryExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = whoscallDirectoryExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
IPHONEOS_DEPLOYMENT_TARGET = 18.5;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = org.reactjs.native.example.whoscall.whoscallDirectoryExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
......@@ -652,15 +463,6 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
2F60E0252E66CCEF00C504BE /* Build configuration list for PBXNativeTarget "whoscallDirectoryExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
2F60E0222E66CCEF00C504BE /* Debug */,
2F60E0232E66CCEF00C504BE /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "whoscall" */ = {
isa = XCConfigurationList;
buildConfigurations = (
......
......@@ -31,11 +31,6 @@
<key>NSAllowsLocalNetworking</key>
<true/>
</dict>
<key>NSUserActivityTypes</key>
<array>
<string>INStartAudioCallIntent</string>
<string>INStartVideoCallIntent</string>
</array>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>RCTNewArchEnabled</key>
......
#if os(iOS)
import Foundation
import CallKit
......@@ -18,7 +19,7 @@ class CallDirectoryHandler: CXCallDirectoryProvider {
// Example: add VIP numbers
// Numbers must be E.164 format (+60 for Malaysia)
let vipNumbers: [(number: Int64, label: String)] = [
(60189884118, "VIP: Wei Yi"),
(60189884118, "Wei Yi"),
(60123456789, "Spam Caller"),
]
......@@ -46,3 +47,4 @@ extension CallDirectoryHandler: CXCallDirectoryExtensionContextDelegate {
NSLog("Call Directory extension error: \(error.localizedDescription)")
}
}
#endif
\ No newline at end of file
......@@ -4,25 +4,20 @@
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>CXCallDirectoryExtensionAttributes</key>
<dict>
<key>CXCallDirectoryExtensionIdentifier</key>
<string>com.yourapp.callid</string>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.callkit.call-directory</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).CallDirectoryHandler</string>
</dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>CXCallDirectoryExtensionAttributes</key>
<dict>
<key>CXCallDirectoryExtensionIdentifier</key>
<string>com.yourapp.callid</string>
</dict>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.callkit.call-directory</string>
<key>NSExtensionPrincipalClass</key>
<string>$(PRODUCT_MODULE_NAME).CallDirectoryHandler</string>
</dict>
<key>RCTNewArchEnabled</key>
<true/>
</dict>
</plist>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment