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

Android开发求助:如何向已保存联系人发送含位置信息的短信

实现向已保存联系人发送含位置信息的短信

一、添加必要权限

在AndroidManifest.xml中声明以下权限,确保应用能发送短信、获取位置及读取联系人:

<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

二、完善联系人模型(修正原代码逻辑问题)

原ContactModel的手机号验证存在逻辑错误,以下是优化后的版本,确保手机号格式统一:

public class ContactModel {
    private int id;
    private String phoneNo;
    private String name;

    // 构造方法
    public ContactModel(int id, String name, String phoneNo) {
        this.id = id;
        this.phoneNo = validatePhoneNumber(phoneNo);
        this.name = name;
    }

    // 验证并格式化手机号:过滤无效字符,统一添加区域码前缀
    private String validatePhoneNumber(String phone) {
        StringBuilder formattedPhone = new StringBuilder();
        // 保留数字和+号,过滤其他字符
        for (char c : phone.toCharArray()) {
            if (Character.isDigit(c) || c == '+') {
                formattedPhone.append(c);
            }
        }
        // 无+号前缀时,默认添加+212(可根据需求修改区域码)
        if (!formattedPhone.toString().startsWith("+")) {
            formattedPhone.insert(0, "+212");
        }
        return formattedPhone.toString();
    }

    // Getter和Setter方法
    public String getPhoneNo() {
        return phoneNo;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

三、实现当前位置获取功能

使用Google推荐的FusedLocationProviderClient获取设备当前经纬度:

private FusedLocationProviderClient fusedLocationClient;
private double currentLatitude;
private double currentLongitude;
private static final int MY_PERMISSIONS_REQUEST_LOCATION = 2;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    fusedLocationClient = LocationServices.getFusedLocationProviderClient(this);
    // 其他初始化代码...
}

// 获取当前位置
private void getCurrentLocation() {
    // 检查位置权限
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, MY_PERMISSIONS_REQUEST_LOCATION);
        return;
    }
    // 获取最后已知位置
    fusedLocationClient.getLastLocation()
            .addOnSuccessListener(this, location -> {
                if (location != null) {
                    currentLatitude = location.getLatitude();
                    currentLongitude = location.getLongitude();
                    // 获取位置后触发联系人选择
                    selectContactAndSendSms();
                } else {
                    Toast.makeText(this, "无法获取当前位置,请检查定位设置", Toast.LENGTH_SHORT).show();
                }
            });
}

四、整合联系人选择与短信发送逻辑

将联系人选择、位置信息、短信发送功能整合,修正原短信代码的权限处理和内容填充:

private static final int MY_PERMISSIONS_REQUEST_SEND_SMS = 1;
private static final int PICK_CONTACT_REQUEST = 3;
private ContactModel selectedContact;
Button sendBtn;

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

    sendBtn = findViewById(R.id.btnSendSMS);
    sendBtn.setOnClickListener(view -> {
        // 点击按钮先获取位置,再选择联系人
        getCurrentLocation();
    });
}

// 调用系统联系人选择器
private void selectContactAndSendSms() {
    Intent pickContactIntent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Phone.CONTENT_URI);
    startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST);
}

// 处理联系人选择结果
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == PICK_CONTACT_REQUEST && resultCode == RESULT_OK) {
        Uri contactUri = data.getData();
        String[] projection = {ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME};
        Cursor cursor = getContentResolver().query(contactUri, projection, null, null, null);
        
        if (cursor != null && cursor.moveToFirst()) {
            int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
            int nameIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
            String phoneNumber = cursor.getString(numberIndex);
            String contactName = cursor.getString(nameIndex);
            
            // 用ContactModel格式化手机号
            selectedContact = new ContactModel(0, contactName, phoneNumber);
            // 开始发送短信
            sendSMSMessage();
            cursor.close();
        }
    }
}

// 权限检查与短信发送触发
protected void sendSMSMessage() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.SEND_SMS)) {
            Toast.makeText(this, "需要短信权限才能发送位置信息", Toast.LENGTH_SHORT).show();
        }
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.SEND_SMS}, MY_PERMISSIONS_REQUEST_SEND_SMS);
    } else {
        sendSmsImpl();
    }
}

// 权限请求结果处理
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_SEND_SMS: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                sendSmsImpl();
            } else {
                Toast.makeText(getApplicationContext(), "未授予短信权限,无法发送短信", Toast.LENGTH_LONG).show();
            }
            break;
        }
        case MY_PERMISSIONS_REQUEST_LOCATION: {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                getCurrentLocation();
            } else {
                Toast.makeText(getApplicationContext(), "未授予位置权限,无法获取当前位置", Toast.LENGTH_LONG).show();
            }
            break;
        }
    }
}

// 实际发送短信逻辑
private void sendSmsImpl() {
    // 校验联系人与位置是否有效
    if (selectedContact == null || currentLatitude == 0 || currentLongitude == 0) {
        Toast.makeText(this, "请先选择联系人并确保位置获取成功", Toast.LENGTH_SHORT).show();
        return;
    }
    // 构建带位置链接的短信内容
    String locationLink = String.format("https://www.google.com/maps/search/?api=1&query=%f,%f", currentLatitude, currentLongitude);
    String smsContent = String.format("我现在的位置:%s", locationLink);
    
    SmsManager smsManager = SmsManager.getDefault();
    // 拆分长短信(超过短信字数限制时自动拆分)
    ArrayList<String> smsParts = smsManager.divideMessage(smsContent);
    smsManager.sendMultipartTextMessage(selectedContact.getPhoneNo(), null, smsParts, null, null);
    
    Toast.makeText(getApplicationContext(), "短信已发送", Toast.LENGTH_LONG).show();
}

五、关键注意事项

  • 权限处理:Android 6.0及以上版本必须动态申请短信、位置、读取联系人权限,不能仅依赖Manifest声明。
  • 位置可靠性:getLastLocation()可能返回null,建议添加位置更新监听,确保获取到实时有效位置。
  • 长短信处理:短信内容过长时,必须用divideMessage拆分后发送,避免发送失败。
  • 联系人来源:示例使用系统联系人选择器,若你有自定义联系人列表,直接传入对应的ContactModel对象即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:45:45