史上最全的隐式Intent解析

时间:2024-05-22 17:51:04

不知不觉已经周五了,后面两天就不再推送文章了,祝大家周末愉快。今天的这篇文章同样来自 刘明渊 的译文,由于篇幅限制,我选取了一些常用的隐式Intent来介绍,完整文章可以点击最下方 “阅读原文” 查看。


刘明渊的博客地址:http://blog.****.net/vanpersie_9987




Intent的真正强大之处在于它的隐式Intent,隐式Intent需要配合Intent-filters使用。隐式Intent足够强大,以至于系统提供了大量的Intent方便开发者启动系统应用程序,本文将介绍一些常用的隐式Intent、以及如何自定义intent-filters以匹配隐式intent。


常用的Intent(Common Intents)


下面将按照启动的目标组件类别介绍隐式Intent:


闹钟类别(Alarm Clock)


  • 启动闹钟(Create an alarm)

要启动闹钟activity,可以这样设定Intent:


Action:ACTION_SET_ALARM

Data URI:

MIME Type:

Extras:

  • EXTRA_HOUR:设定小时

  • EXTRA_MINUTES:设定分钟

  • EXTRA_MESSAGE:设定自定义消息

  • EXTRA_DAYS:设定每周的周几重复响铃。该字段的值应定义成ArrayList,每个元素是Calendar类中的静态字段(如Calendar.Monday)。对于那些一次性响铃,无需设置这个extra。

  • EXTRA_RINGTONE:设定闹钟铃声。该字段的值应设定成一个scheme为 content: 的URI类型,该URI指向了一个音频文件的地址;您也可以将值设定为 VALUE_RINGTONE_SILENT,这表示将闹钟设为静音。

  • EXTRA_VIBRATE:设定是否响铃的同时震动。该字段的值为boolean类型。

  • EXTRA_SKIP_UI:设定启动系统闹钟应用程序时,是否跳过UI界面,值为boolean类型,若为true,表示不显示设定闹钟的dialog对话框,而直接进入设置闹钟的activity。


示例:

public void createAlarm(String message, int hour, int minutes) {
   Intent intent = new Intent(AlarmClock.ACTION_SET_ALARM)            .putExtra(AlarmClock.EXTRA_MESSAGE, message)            .putExtra(AlarmClock.EXTRA_HOUR, hour)            .putExtra(AlarmClock.EXTRA_MINUTES, minutes);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }


若为Intent指定的action为ACTION_SET_ALARM,则需要在manifest中配置如下权限:

<uses-permission
android:name="com.android.alarm.permission.SET_ALARM" />


可以响应该Intent的intent-filter如下:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_ALARM" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


  • 启动计时器(Create a timer)

!请注意:该Intent只兼容 Android 4.4 (API level 19) 及以上版本的设备。


要启动计时器,可以这样设定Intent:


Action:ACTION_SET_TIMER

Data URI:

MIME Type:

Extras:

  • EXTRA_LENGTH:设置倒计时的秒数

  • EXTRA_MESSAGE:设置到时消息

  • EXTRA_SKIP_UI:设定启动系统计时器应用程序时,是否跳过UI界面,值为boolean类型,若为true,表示不显示设定计时器的设置dialog对话框,而直接进入计时器的activity。


示例:

public void startTimer(String message, int seconds) {
   Intent intent = new Intent(AlarmClock.ACTION_SET_TIMER)            .putExtra(AlarmClock.EXTRA_MESSAGE, message)            .putExtra(AlarmClock.EXTRA_LENGTH, seconds)            .putExtra(AlarmClock.EXTRA_SKIP_UI, true);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }


若为Intent指定的action为ACTION_SET_TIMER,则需要在manifest中配置如下权限:

<uses-permission
android:name="com.android.alarm.permission.SET_ALARM" />


可以响应该Intent的intent-filter如下:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SET_TIMER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


  • 显示设置的所有闹钟(Show all alarms)

!请注意:该Intent只兼容 Android 4.4 (API level 19) 及以上版本的设备。


Action:ACTION_SHOW_ALARMS

Data URI:

MIME Type:


示例:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SHOW_ALARMS" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


日期类别(Calendar)


  • 添加日历事件(Add a calendar event)


Action:ACTION_INSERT

Data URI:Events.CONTENT_URI

MIME Type:”vnd.android.cursor.dir/event”

Extras:

  • EXTRA_EVENT_ALL_DAY:该键所对应的值是boolean类型,表示事件是否为全天候事件。

  • EXTRA_EVENT_BEGIN_TIME:代表事件的起始时间,值为 从2000年到设定起始时间所经历的毫秒数(milliseconds since epoch)。

  • EXTRA_EVENT_END_TIME :代表事件的结束时间,值为 从2000年到设定结束时间所经历的毫秒数(milliseconds since epoch)。

  • TITLE:事件的标题

  • DESCRIPTION:事件的描述

  • EVENT_LOCATION:事件发生的地点

  • EXTRA_EMAIL:将事件邮件的形式发送,值为邮箱地址,可同时发送给多人,邮箱地址以逗号分隔。欲了解更多关于发送邮件的细节,您可以参考这个类:CalendarContract.EventsColumns


示例:

public void addEvent(String title, String location,
         Calendar begin, Calendar end) {
   Intent intent = new Intent(Intent.ACTION_INSERT)            .setData(Events.CONTENT_URI)            .putExtra(Events.TITLE, title)            .putExtra(Events.EVENT_LOCATION, location)            .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, begin)            .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, end);    
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }

可以匹配上述intent的intent-filters:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.INSERT" />
        <data android:mimeType="vnd.android.cursor.dir/event" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


相机类别(Camera)


  • 使用相机拍照或录像并返回结果(Capture a picture or video and return it)


Action:ACTION_IMAGE_CAPTURE 或 ACTION_VIDEO_CAPTURE

Data URI Scheme:

MIME Type:

Extras:EXTRA_OUTPUT,该键所对应的值是一个Uri对象,它表示通过相机应用所照的相片或录的视频的存储地址。您可以在onActivityResult()方法中通过该Uri获取刚照的相片。

!请注意:通过ACTION_IMAGE_CAPTURE启动activity并返回的照片是一个键为”data”的Bitmap类型的略缩图(downscaled copy (a thumbnail) of the photo)


示例如下:

static final int REQUEST_IMAGE_CAPTURE = 1;
static final Uri mLocationForPhotos;
public void capturePhoto(String targetFilename) {
   Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);    intent.putExtra(MediaStore.EXTRA_OUTPUT,
           Uri.withAppendedPath(mLocationForPhotos, targetFilename));
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivityForResult(intent, REQUEST_IMAGE_CAPTURE);    } } @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
       Bitmap thumbnail = data.getParcelable("data");
       // Do other work with full size photo saved in mLocationForPhotos        ...    } }

关于如何通过这个Intent拍照、录像,以及如何获得存储照片、录像的Uri地址,您可以参考这些Training:


  • Taking Photos Simply:

https://developer.android.com/training/camera/photobasics.html

  • Taking Videos Simply:

https://developer.android.com/training/camera/videobasics.html


示例intent-filter:

<activity ...>
    <intent-filter>
        <action android:name="android.media.action.IMAGE_CAPTURE" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


  • 启动相机应用的照相模式(Start a camera app in still image mode)


Action:INTENT_ACTION_STILL_IMAGE_CAMERA

Data URI Scheme:

MIME Type:

Extras:


示例:

public void capturePhoto() {
   Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivityForResult(intent);    } }

intent-filter:

<activity ...>
    <intent-filter>
        <action android:name="android.media.action.STILL_IMAGE_CAMERA" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


  • 启动相机应用的录像模式(Start a camera app in video mode)


Action:INTENT_ACTION_VIDEO_CAMERA

Data URI Scheme:

MIME Type:

Extras:


示例:

public void capturePhoto() {
   Intent intent = new Intent(MediaStore.INTENT_ACTION_VIDEO_CAMERA);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivityForResult(intent);    } }

intent-filter:

<activity ...>
    <intent-filter>
        <action android:name="android.media.action.VIDEO_CAMERA" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>


通讯录类别(Contacts/People App)


  • 选择联系人(Select a contact)

在onActivityResult()中可获取您选择的联系人,如果只是通过Contacts Provider读取联系人信息,则无需申请READ_CONTACTS权限。


Action:ACTION_PICK

Data URI Scheme:None

MIME Type:Contacts.CONTENT_TYPE


示例:

static final int REQUEST_SELECT_CONTACT = 1;

public void selectContact() {
   Intent intent = new Intent(Intent.ACTION_PICK);    intent.setType(ContactsContract.Contacts.CONTENT_TYPE);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivityForResult(intent, REQUEST_SELECT_CONTACT);    } } @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   if (requestCode == REQUEST_SELECT_CONTACT && resultCode == RESULT_OK) {
       Uri contactUri = data.getData();
       // Do something with the selected contact at contactUri        ...    } }

关于如何处理返回的Uri对象contactUri ,您可以访问这个Training:Retrieving Details for a Contact:

https://developer.android.com/training/contacts-provider/retrieve-details.html


  • 获得具体联系人信息(Select specific contact data)


Action:ACTION_PICK

Data URI Scheme:

MIME Type:

  • CommonDataKinds.Phone.CONTENT_TYPE,表示获取联系人号码

  • CommonDataKinds.Email.CONTENT_TYPE,表示获取联系人Email

  • CommonDataKinds.StructuredPostal.CONTENT_TYPE,表示获取联系人的邮寄地址

  • 通过ContactsContract.CommonDataKinds中的其他字段,还可以获取更多联系人信息。


示例:

史上最全的隐式Intent解析


  • 查看联系人(View a contact)


Action:ACTION_VIEW

Data URI Scheme:content:<URI>,该Uri指向了查看的联系人地址,有两种方法可获得该Uri:

MIME Type:


示例:

public void viewContact(Uri contactUri) {
   Intent intent = new Intent(Intent.ACTION_VIEW, contactUri);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }


  • 编辑联系人信息(Edit an existing contact)


Action:ACTION_EDIT

Data URI Scheme:content:<URI>,获取该Uri的方式和权限与上一小节的获取方式一致。

MIME Type:由Uri决定。

Extras:ContactsContract.Intents.Insert


示例:

public void editContact(Uri contactUri, String email) {
   Intent intent = new Intent(Intent.ACTION_EDIT);    intent.setData(contactUri);    intent.putExtra(Intents.Insert.EMAIL, email);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }

更多关于编辑联系人的方法,您可以参考这个Training:Modifying Contacts Using Intents:

https://developer.android.com/training/contacts-provider/modify-data.html


  • 新增联系人(Insert a contact)


Action:ACTION_INSERT

Data URI Scheme:

MIME Type:Contacts.CONTENT_TYPE

Extras:ContactsContract.Intents.Insert


示例:

public void insertContact(String name, String email) {
   Intent intent = new Intent(Intent.ACTION_INSERT);    intent.setType(Contacts.CONTENT_TYPE);    intent.putExtra(Intents.Insert.NAME, name);    intent.putExtra(Intents.Insert.EMAIL, email);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }


电话类别(Phone)


  • 初始化电话拨号(Initiate a phone call)

您可以通过 ACTION_DIAL这个action打开电话应用程序的拨号界面,并把电话号码作为参数到拨号框中,用户点击“拨打”按钮开始拨号。这无需任何权限。


您也可以通过ACTION_CALL这个action直接拨打电话,而无需点击“拨打”按钮。这需要添加如下权限:

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

Intent的具体设置方式如下:


Action:

  • ACTION_DIAL,打开拨号界面。

  • ACTION_CALL,直接拨打电话。

Data URI Scheme:

  • tel:<phone-number>

  • voicemail:<phone-number>

MIME Type:


合法的电话号码格式请参照这个链接:the IETF RFC 3966:

http://tools.ietf.org/html/rfc3966


合法的电话号码形如:

  • tel:2125551212

  • tel:(212) 555 1212


示例:

public void dialPhoneNumber(String phoneNumber) {
   Intent intent = new Intent(Intent.ACTION_DIAL);    intent.setData(Uri.parse("tel:" + phoneNumber));
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }


短消息类别(Text Messaging)


  • 创建短信/彩信 并携带附件(Compose an SMS/MMS message with attachment)


Action:

  • ACTION_SENDTO

  • ACTION_SEND

  • ACTION_SEND_MULTIPLE


Data URI Scheme:

  • sms:<phone_number>

  • smsto:<phone_number>

  • mms:<phone_number>

  • mmsto:<phone_number>

以上四种方式效果相同


MIME Type:

  • "text/plain"

  • "image/*"

  • "video/*"


Extras:

  • "subject",该键对应值是一个字符串,表示发送短信的标题(通常只适用于发短信)。

  • "sms_body",该键对应值是一个字符串,表示消息内容。

  • EXTRA_STREAM,该键对应的值是一个Uri地址,它指向了附加文件,若action为ACTION_SEND_MULTIPLE,则这个值应该是一个ArrayList<Uri>对象。


示例:

public void composeMmsMessage(String message, Uri attachment) {
   Intent intent = new Intent(Intent.ACTION_SENDTO);    intent.setType(HTTP.PLAIN_TEXT_TYPE);    intent.putExtra("sms_body", message);    intent.putExtra(Intent.EXTRA_STREAM, attachment);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }

若您通过intent打开的确实是一个发送短消息的应用(而不是Email或是社交类的应用),那么可以按如下方式操作:

public void composeMmsMessage(String message, Uri attachment) {
   Intent intent = new Intent(Intent.ACTION_SEND);
   // This ensures only SMS apps respond    intent.setData(Uri.parse("smsto:"));    intent.putExtra("sms_body", message);    intent.putExtra(Intent.EXTRA_STREAM, attachment);
   if (intent.resolveActivity(getPackageManager()) != null) {        startActivity(intent);    } }

与之匹配的intent-filter配置如下:

<activity ...>
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="text/plain" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</
activity>




如果你有好的技术文章想和大家分享,欢迎向我的公众号投稿,投稿具体细节请在公众号主页点击“投稿”菜单查看。


欢迎长按下图 -> 识别图中二维码或者扫一扫关注我的公众号:

史上最全的隐式Intent解析