You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过代码批量添加号码至手机并标记为已拦截?

问题描述

我正在开发一款应用,用于将1800+团队成员收到的垃圾及诈骗号码添加到手机中并标记为拦截状态,以便在团队内共享使用避免骚扰。目前已实现从文件导入号码至通讯录,但无法完成标记拦截的操作,以下是添加联系人的代码片段:

import android.Manifest;
import android.content.ContentProviderOperation;
import android.content.ContentValues;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.BlockedNumberContract;
import android.provider.ContactsContract;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private static final int READ_CONTACTS_PERMISSION_REQUEST = 1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Request READ_CONTACTS and WRITE_CONTACTS permissions if not granted
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS)
                != PackageManager.PERMISSION_GRANTED ||
                ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS)
                        != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS},
                    READ_CONTACTS_PERMISSION_REQUEST);
        } else {
            addBlockedNumbersToContacts();
        }
    }

    private void addBlockedNumbersToContacts() {
        try {
            InputStream inputStream = getAssets().open("numbers.txt");
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

            ArrayList<String> blockedNumbers = new ArrayList<>();
            String line;
            while ((line = reader.readLine()) != null) {
                String normalizedNumber = line.trim();
                if (!normalizedNumber.isEmpty()) {
                    blockedNumbers.add(normalizedNumber);
                }
            }

            reader.close();

            for (String number : blockedNumbers) {
                // Add the number to contacts with a custom label "Blocked"
                addNumberToContacts(number, "Blocked");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void addNumberToContacts(String phoneNumber, String label) {
        // Prepare the contact values
        ArrayList<ContentProviderOperation> ops = new ArrayList<>();
        int rawContactInsertIndex = ops.size();

        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
                .build());

        // Add the phone number to the contact data with the custom label
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, rawContactInsertIndex)
                .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM)
                .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, label)
                .build());


        try {
            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
            Log.d("Contact", "Number added to contacts: " + phoneNumber);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == READ_CONTACTS_PERMISSION_REQUEST) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
                    && grantResults[1] == PackageManager.PERMISSION_GRANTED) {
                addBlockedNumbersToContacts();
            } else {
               
            }
        }
    }
}
实现号码拦截标记的方案

Android系统提供BlockedNumberContract API来管理系统级拦截号码,你可以基于现有代码扩展实现拦截功能,具体步骤如下:

1. 添加必要权限

除了现有通讯录权限,还需在AndroidManifest.xml中声明拦截号码的权限:

<uses-permission android:name="android.permission.READ_BLOCKED_NUMBERS" />
<uses-permission android:name="android.permission.WRITE_BLOCKED_NUMBERS" />

注意:WRITE_BLOCKED_NUMBERS权限在Android 7.0(API 24)及以上需要动态申请,需和通讯录权限一起处理。

2. 更新权限申请逻辑

修改onCreate和onRequestPermissionsResult方法,加入拦截权限的申请判断:

private static final int PERMISSION_REQUEST_CODE = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String[] requiredPermissions = {
            Manifest.permission.READ_CONTACTS,
            Manifest.permission.WRITE_CONTACTS,
            Manifest.permission.READ_BLOCKED_NUMBERS,
            Manifest.permission.WRITE_BLOCKED_NUMBERS
    };

    boolean allPermissionsGranted = true;
    for (String perm : requiredPermissions) {
        if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED) {
            allPermissionsGranted = false;
            break;
        }
    }

    if (!allPermissionsGranted) {
        ActivityCompat.requestPermissions(this, requiredPermissions, PERMISSION_REQUEST_CODE);
    } else {
        addBlockedNumbersToContactsAndBlock();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    if (requestCode == PERMISSION_REQUEST_CODE) {
        boolean allGranted = true;
        for (int result : grantResults) {
            if (result != PackageManager.PERMISSION_GRANTED) {
                allGranted = false;
                break;
            }
        }
        if (allGranted) {
            addBlockedNumbersToContactsAndBlock();
        } else {
            // 处理权限被拒绝的情况,比如弹窗提示用户开启必要权限
        }
    }
}

3. 新增拦截号码的方法

添加专门用于拦截号码的工具方法,处理系统拦截逻辑:

private boolean blockPhoneNumber(String phoneNumber) {
    ContentValues values = new ContentValues();
    values.put(BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER, phoneNumber);
    // 可选:标准化号码为E164格式(如+8613xxxxxxxxx),提升拦截准确性
    values.put(BlockedNumberContract.BlockedNumbers.COLUMN_E164_NUMBER, normalizePhoneNumber(phoneNumber));

    try {
        Uri insertedUri = getContentResolver().insert(BlockedNumberContract.BlockedNumbers.CONTENT_URI, values);
        return insertedUri != null;
    } catch (SecurityException e) {
        Log.e("BlockNumber", "拦截号码失败: " + phoneNumber, e);
        return false;
    }
}

// 可选:标准化号码格式,去除非数字字符并添加国家码(根据实际需求调整)
private String normalizePhoneNumber(String number) {
    String cleanNumber = number.replaceAll("[^0-9]", "");
    // 假设国内号码,自动添加+86前缀
    if (cleanNumber.startsWith("1") && cleanNumber.length() == 11) {
        return "+86" + cleanNumber;
    }
    return cleanNumber;
}

4. 修改导入流程,同时完成添加联系人与拦截

更新原有的导入方法,在添加联系人后调用拦截方法:

private void addBlockedNumbersToContactsAndBlock() {
    try {
        InputStream inputStream = getAssets().open("numbers.txt");
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));

        ArrayList<String> blockedNumbers = new ArrayList<>();
        String line;
        while ((line = reader.readLine()) != null) {
            String normalizedNumber = line.trim();
            if (!normalizedNumber.isEmpty()) {
                blockedNumbers.add(normalizedNumber);
            }
        }

        reader.close();

        for (String number : blockedNumbers) {
            // 先添加到通讯录
            addNumberToContacts(number, "Blocked");
            // 再标记为拦截
            boolean isBlocked = blockPhoneNumber(number);
            Log.d("BlockStatus", "号码 " + number + " 拦截状态: " + isBlocked);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

额外注意事项

  • 系统版本限制:BlockedNumberContract仅支持Android 7.0(API 24)及以上设备,低于该版本的设备需要采用替代方案,比如调用系统拦截Intent或依赖第三方安全应用接口。
  • 重复拦截检查:可以先查询号码是否已被拦截,避免重复操作:
private boolean isNumberBlocked(String phoneNumber) {
    String selection = BlockedNumberContract.BlockedNumbers.COLUMN_ORIGINAL_NUMBER + " = ?";
    String[] selectionArgs = {phoneNumber};
    try (var cursor = getContentResolver().query(BlockedNumberContract.BlockedNumbers.CONTENT_URI, null, selection, selectionArgs, null)) {
        return cursor != null && cursor.getCount() > 0;
    }
}
  • 性能优化:批量处理1800+号码时,建议使用异步任务(如Coroutine)避免阻塞主线程,提升应用流畅度。

内容的提问来源于stack exchange,提问作者curious07

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 03:25:55