//使用ACTION_SENDTO而不是ACTION_SENDIntent intent = new Intent(Intent.ACTION_SENDTO);//指定URI使用smsto:协议,协议后面是接收短信的对象Uri uri = Uri.parse("smsto:10086");intent.setData(uri);//设置消息体intent.putExtra("sms_body", "手头有点紧,借点钱吧~~");ComponentName componentName = intent.resolveActivity(getPackageManager());if(componentName != null){ startActivity(intent);}在构造发送短信的URI时,前面是smsto:协议,后面跟的是接收短信的对方的手机号。如果在构建URI时,只写了smsto:,而没有写后面的手机的号的话,那么该intent也可以成功启动短信应用,不过这种情形下,在启动了短信应用之后,还需要我们自己再手动输入接收信息的手机号。我们通过key为sms_body的extra设置短信的内容。
//使用ACTION_SENDTO而不是ACTION_SENDIntent intent = new Intent(Intent.ACTION_SENDTO);//指定URI使用mailto:协议,确保只有邮件应用能接收到此intent对象Uri uri = Uri.parse("mailto:");intent.setData(uri);String[] addresses = {"zhangsan@126.com", "lisi@126.com"};String[] cc = {"boss@126.com"};String[] bcc = {"girlfriend@126.com"};String subject = "加班";String content = "国庆正常上班~~";//设置邮件的接收方intent.putExtra(Intent.EXTRA_EMAIL, addresses);//设置邮件的抄送方intent.putExtra(Intent.EXTRA_CC, cc);//设置邮件的密送方intent.putExtra(Intent.EXTRA_BCC, bcc);//设置邮件标题intent.putExtra(Intent.EXTRA_SUBJECT, subject);//设置邮件内容intent.putExtra(Intent.EXTRA_TEXT, content);//设置邮件附件//intent.putExtra(Intent.EXTRA_STREAM, Uri.parse(...));ComponentName componentName = intent.resolveActivity(getPackageManager());if(componentName != null){ startActivity(intent);}启动邮件应用后的截图如下所示:
我们分别通过key为Intent.EXTRA_EMAIL、Intent.EXTRA_CC和Intent.EXTRA_BCC的extra依次设置邮件的接收方、抄送方、密送方,其值均为String数组。我们通过key为Intent.EXTRA_SUBJECT的extra设置邮件标题,通过key为Intent.EXTRA_TEXT的extra设置邮件内容。如果想发送附件,那么可以将附件封装成Uri的形式,然后通过key为Intent.EXTRA_STREAM的extra设置邮件附件。
需要注意的是,在执行了startActivity(intent)之后,虽然邮件应用启动打开了,但是邮件没有直接发出去,需要我们再点击一下右上角的发送按钮才能将邮件发出去。
打电话
要想通过Intent打电话,我们有两个可以使用的action:Intent.ACTION_DIAL和Intent.ACTION_CALL,二者有一定的区别。
如果使用Intent.ACTION_DIAL作为intent对象的action,那么当执行startActivity(intent)之后,会启动打电话应用,并且会自动输入指定的手机号,但是不会自动拨打,需要我们手动按下拨打按钮才能真正给对方打电话。
如果使用Intent.ACTION_CALL作为intent对象的action,那么当执行startActivity(intent)之后,会启动打电话应用,并且直接拨打我们指定的手机号,无需我们再手动按下拨打按钮。但是需要注意的是,该action需要权限android.permission.CALL_PHONE,如果在应用的AndroidManifest.xml文件中没有添加该权限,那么当指定到startActivity(intent)这句代码的时候,就会抛出异常,应用崩溃退出。
以下是示例代码:
//Intent.ACTION_DIAL只拨号,不打电话//Intent intent = new Intent(Intent.ACTION_DIAL);//Intent.ACTION_CALL直接拨打指定电话,需要android.permission.CALL_PHONE权限Intent intent = new Intent(Intent.ACTION_CALL);Uri uri = Uri.parse("tel:10086");intent.setData(uri);ComponentName componentName = intent.resolveActivity(getPackageManager());if(componentName != null){ startActivity(intent);}在该示例代码中,我们使用了Intent.ACTION_CALL作为intent对象的action,并且在AndroidManifest.xml中添加了如下权限:
//表示用于拍照的requestCode private final int REQUEST_CODE_IMAGE_CAPTURE = 1; //我们存储照片的输出路径,以便后续使用 private Uri imageOutputUri = null; //拍照 private void captureImage(){ PackageManager pm = getPackageManager(); //先判断本机是否在硬件上有摄像能力 if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){ Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); ComponentName componentName = intent.resolveActivity(pm); //判断手机上有无摄像机应用 if(componentName != null){ //创建图片文件,以便于通过Uri.fromFile()生成对应的Uri File imageFile = createImageFile(); if(imageFile != null){//根据imageFile生成对应的UriimageOutputUri = Uri.fromFile(imageFile);//利用该Uri作为拍照完成后照片的存储路径,注意,一旦设置了存储路径,我们就不能获取缩略图了intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputUri);//调用startActivityForResult()方法,以便在onActivityResult()方法中进行相应处理startActivityForResult(intent, REQUEST_CODE_IMAGE_CAPTURE); }else{Toast.makeText(this, "无法创建图像文件!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "未在本机找到Camera应用,无法拍照!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "本机没有摄像头,无法拍照!", Toast.LENGTH_LONG).show(); } } //创建图片文件,以便于通过Uri.fromFile()生成对应的Uri private File createImageFile(){ File image = null; //用时间戳拼接文件名称,防止文件重名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); try{ image = File.createTempFile(imageFileName, //前缀".jpg", //后缀storageDir //文件夹 ); }catch (IOException e){ image = null; e.printStackTrace(); Log.e("DemoLog", e.getMessage()); } return image; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { //首先判断是否正确完成 if(resultCode == RESULT_OK){ switch (requestCode){ case REQUEST_CODE_IMAGE_CAPTURE://此处,我们可以通过imageOutputUri获取到我们想要的图片String imagePath = imageOutputUri.toString();Log.i("DemoLog", "照片路径是: " + imagePath);Toast.makeText(this, "照片路径是: " + imagePath, Toast.LENGTH_LONG).show();//以下代码尝试获取缩略图//如果设置MediaStore.EXTRA_OUTPUT作为extra的时候,那么此处的intent为null,需要判断if(intent != null){Bitmap thumbnail = intent.getParcelableExtra("data");//有的手机并不会给拍照的图片生成缩略图,所以此处也要判断if(thumbnail != null){Log.i("DemoLog", "得到缩略图");}} default:break; } } }我们分析一下上面的代码片段:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"></uses-permission>我们利用上面生成的图片文件生成了对应的Uri,将其存储在Activity中类型为Uri的字段imageOutputUri中,之后我们执行了intent.putExtra(MediaStore.EXTRA_OUTPUT, imageOutputUri),利用该Uri作为拍照完成后照片的存储路径。
//表示用于录视频的requestCode private final int REQUEST_CODE_VIDEO_CAPTURE = 2; //我们存储视频的输出路径,以便后续使用 private Uri videoOutputUri = null; //摄像 private void captureVideo(){ PackageManager pm = getPackageManager(); //先判断本机是否在硬件上有摄像能力 if(pm.hasSystemFeature(PackageManager.FEATURE_CAMERA)){ //将intent的action设置为MediaStore.ACTION_VIDEO_CAPTURE Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE); ComponentName componentName = intent.resolveActivity(pm); //判断手机上有无摄像机应用 if(componentName != null){ //创建视频文件,以便于通过Uri.fromFile()生成对应的Uri File videoFile = createVideoFile(); if(videoFile != null){//根据videoFile生成对应的UrivideoOutputUri = Uri.fromFile(videoFile);//利用该Uri作为摄像完成后视频的存储路径intent.putExtra(MediaStore.EXTRA_OUTPUT, videoOutputUri);//调用startActivityForResult()方法,以便在onActivityResult()方法中进行相应处理startActivityForResult(intent, REQUEST_CODE_VIDEO_CAPTURE); }else{Toast.makeText(this, "无法创建视频文件!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "未在本机找到Camera应用,无法摄像!", Toast.LENGTH_LONG).show(); } }else{ Toast.makeText(this, "本机没有摄像头,无法摄像!", Toast.LENGTH_LONG).show(); } } //创建视频文件,以便于通过Uri.fromFile()生成对应的Uri private File createVideoFile(){ File videoFile = null; //用时间戳拼接文件名称,防止文件重名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String imageFileName = "MP4" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_MOVIES); try{ videoFile = File.createTempFile(imageFileName, //前缀".mp4", //后缀storageDir //文件夹 ); }catch (IOException e){ videoFile = null; e.printStackTrace(); Log.e("DemoLog", e.getMessage()); } return videoFile; } @Override protected void onActivityResult(int requestCode, int resultCode, Intent intent) { //首先判断是否正确完成 if(resultCode == RESULT_OK){ switch (requestCode){ case REQUEST_CODE_VIDEO_CAPTURE://如果设置MediaStore.EXTRA_OUTPUT作为extra的时候,//在有的手机上,此处的intent为不为null,但是在有的手机上却为null,//所以不建议从intent.getData()中获取视频路径//我们应该自己记录videoOutputUri来得知视频路径,下面注释的代码不建议使用/*if(intent != null){Uri videoUri = intent.getData();if(videoUri != null){//路径格式如content://media/external/video/media/130025Log.i("DemoLog", "视频路径是: " + videoUri.toString());}}*/String videoPath = videoOutputUri.toString();//1.如果没有设置MediaStore.EXTRA_OUTPUT作为视频文件存储路径,那么路径格式如下所示:// 路径格式如content://media/external/video/media/130025//2.如果设置了MediaStore.EXTRA_OUTPUT作为视频文件存储路径,那么路径格式如下所示:// 路径格式如file:///storage/sdcard0/Android/data/com.ispring.commonintents/files/Movies/MP420150919_184132_533002075.mp4Log.i("DemoLog", "视频路径是: " + videoPath);Toast.makeText(this, "视频路径是: " + videoPath, Toast.LENGTH_LONG).show();break; default:break; } } }可以看到上面启动Camera摄像的代码与拍照的代码几乎完全一样,具体解释参见对拍照代码的描述。在该示例代码中,我们通过MediaStore.EXTRA_OUTPUT设置了视频的存放路径,拍照的时候我们也通过它设置了照片的输出路径,但是二者稍有区别: