Android Jetpack(四) 行为

image.png

1、CameraX - 轻松地向应用中添加相机功能

CameraX 是一个 Jetpack 支持库,旨在帮助您简化相机应用的开发工作。它提供一致且易于使用的 API 界面,适用于大多数 Android 设备,并可向后兼容至 Android 5.0(API 级别 21)。
CameraX Extensions 是可选插件,通过该插件,您可以在支持的设备上向自己的应用中添加人像、HDR、夜间模式和美颜等效果。

主要优势

易用性

CameraX 引入了多个用例,使您可以专注于需要完成的任务,而无需花时间处理不同设备之间的细微差别

确保各设备间的一致性

自动化 CameraX 测试实验室可确保在多种类型的设备和多个制造商之间实现一致的 API 体验。

新的相机体验

CameraX 有一个名为 Extensions 的可选插件,您只需两行代码,便可借助该插件使用与设备自带的原生相机应用相同的特性和功能。

首批可用功能包括人像、HDR、夜间模式和美颜。这些功能可在受支持的设备上使用。

Codelab

CameraX 使用入门

代码示例

官方 CameraX 示例应用

2、下载管理器- 安排和管理大量下载任务

3、媒体和播放- 用于媒体播放和路由(包括 Google Cast)的向后兼容 API

在 Android 中,您可以从零开始构建自己的播放器,也可以从以下选项中进行选择:

  • MediaPlayer 类提供准系统播放器的基本功能,支持最常见的音频/视频格式和数据源。
  • ExoPlayer 是一个提供低层级 Android 音频 API 的开放源代码库。ExoPlayer 支持 DASH 和 HLS 流等高性能功能,这些功能在 MediaPlayer 中未提供。您可以自定义 ExoPlayer 代码,从而轻松添加新组件。ExoPlayer 只能用于 Android 4.1 及更高版本。

media-compat 库

media-compat 库包含可帮助您构建音频和视频应用的类。这些类与运行 Android 2.3(API 级别 9)及更高版本的设备兼容。它们还可与其他 Android 功能配合使用,以打造舒适亲切的 Android 体验。

媒体会话和媒体控制器的建议实现方式是 MediaSessionCompatMediaControllerCompat 类,它们在 media-compat 支持库中定义。它们取代了 Android 5.0(API 级别 21)中引入的早期版本的 MediaSessionMediaController 类。compat 类提供相同的功能,但可让您更轻松地开发应用,因为您只需写入一个 API。该库通过将媒体会话方法转换为更低版本平台上的等效方法(可用时)来保证向后兼容性。

如果您已经有使用旧类的实际应用,我们建议更新到 compat 类

衡量性能

在 Android 8.0(API 级别 26)及更高版本中,getMetrics() 方法可用于某些媒体类。它会返回一个包含配置和性能信息的 PersistableBundle 对象(表示为属性和值的对应关系)。可以为这些媒体类定义 getMetrics() 方法:

4、通知 - 提供向后兼容的通知 API,支持 Wear 和 Auto

通知的设计由系统模板决定,您的应用只需定义模板各部分的内容。通知的某些详细信息仅在展开视图中显示。

image

图 7. 包含基本详情的通知

图 7 展示了通知最常见的部分,具体如下所示:

  1. 小图标:此为必要图标,通过 setSmallIcon() 设置。
  2. 应用名称:此由系统提供。
  3. 时间戳:此由系统提供,不过您可以通过 setWhen() 进行替换,或使用 setShowWhen(false) 将其隐藏。
  4. 大图标:此为可选图标(通常仅用于联系人照片;请勿将其用于应用图标),通过 setLargeIcon() 设置。
  5. 标题:此为可选内容,通过 setContentTitle() 设置。
  6. 文本:此为可选内容,通过 setContentText()设置。

版本差异

从 Android 7.0(API 级别 24)开始,您可以添加操作来回复消息,或者直接从通知中输入其他文本。
从 Android 10(API 级别 29)开始,平台可以自动生成操作按钮,此类按钮包含基于 Intent 的建议操作。

在 Android 8.0 及更高版本上,用户可以更改每个渠道的重要性
可能的重要性级别如下:
紧急:发出声音并以浮动通知的形式显示。
高:发出声音。
中:不发出声音。
低:不发出声音,也不在状态栏中显示。

以下是最明显的 Android 通知行为变化的摘要。

Android 4.1(API 级别 16)

引入了展开式通知模板(称为通知样式),可以提供较大的通知内容区域来显示信息。用户可以使用单指向上/向下滑动的手势来展开通知。
还支持以按钮形式向通知添加其他操作。
允许用户在设置中按应用关闭通知。

Android 4.4(API 级别 19 和 20)

向 API 中添加了通知侦听器服务
API 级别 20 中添加了对 Android Wear(现称为 Wear OS)的支持。

Android 5.0(API 级别 21)

引入了锁定屏幕和浮动通知。
用户现在可以将手机设置为“请勿打扰”模式,并配置当设备处于“仅限优先事项”模式时,哪些通知可以打扰他们。
向 API 集添加了通知是否在锁定屏幕上显示的方法 (setVisibility()),以及指定通知文本的“公开”版本的方法。
添加了 setPriority() 方法,告知系统该通知应具有的“干扰性”(例如,将其设置为“高”,可使该通知以浮动通知的形式显示)。
Android Wear(现称为 Wear OS)设备添加了通知堆栈支持。使用 setGroup() 将通知放入堆栈。请注意,平板电脑和手机尚不支持通知堆栈。通知堆栈以后会称为组或 Bundle。

Android 7.0(API 级别 24)

重新设计了通知模板的样式,以强调主打图像和头像。
添加了三个通知模板:一个用于消息应用,另外两个用于使用可扩展选项和其他系统装饰来装饰自定义内容视图。
向手持设备(手机和平板电脑)添加了对通知组的支持。使用与 Android 5.0(API 级别 21)中引入的 Android Wear(现称为 Wear OS)通知堆栈相同的 API。
用户可以使用内联回复直接在通知内回复(用户可以输入文本,然后将其发送给通知的父级应用)。

Android 8.0(API 级别 26)

现在必须将单个通知放入特定渠道中。
用户现在可以按渠道关闭通知,而不是关闭应用的所有通知。
包含活动通知的应用会在主屏幕/启动器屏幕上的应用图标上方显示通知“标志”。
现在,用户可以暂停抽屉式通知栏中的通知。您可以为通知设置自动超时。
您还可以设置通知的背景颜色。
与通知行为相关的部分 API 已从 Notification 移至 NotificationChannel。例如,对 Android 8.0 及更高版本使用 NotificationChannel.setImportance(),而不是 NotificationCompat.Builder.setPriority()。

创建通知

dependencies {
        implementation "com.android.support:support-compat:28.0.0"
    }

设置通知内容 ,

//CHANNEL_ID:渠道 ID
   var builder = NotificationCompat.Builder(this, CHANNEL_ID)
//小图标
            .setSmallIcon(R.drawable.notification_icon)
//标题
            .setContentTitle(textTitle)
//正文
            .setContentText(textContent)
//更长的可展开的通知
//创建包含可展开详情的通知(https://developer.android.google.cn/training/notify-user/expanded)。

.setStyle(NotificationCompat.BigTextStyle()
                    .bigText("Much longer text that cannot fit one line..."))
//优先级
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)

创建渠道并设置重要性

private fun createNotificationChannel() {
        // Create the NotificationChannel, but only on API 26+ because
        // the NotificationChannel class is new and not in the support library
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val name = getString(R.string.channel_name)
            val descriptionText = getString(R.string.channel_description)
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
                description = descriptionText
            }
            // Register the channel with the system
            val notificationManager: NotificationManager =
                getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
            notificationManager.createNotificationChannel(channel)
        }
    }

设置通知的点按操作

 // Create an explicit intent for an Activity in your app
    val intent = Intent(this, AlertDetails::class.java).apply {
        flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
    }
    val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)

    val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            // Set the intent that will fire when the user taps the notification
            .setContentIntent(pendingIntent)
            .setAutoCancel(true)

请注意,该代码会调用 setAutoCancel(),它会在用户点按通知后自动移除通知

显示通知

要显示通知,请调用 NotificationManagerCompat.notify(),并将通知的唯一 ID 和 NotificationCompat.Builder.build()的结果传递给它。例如:

    with(NotificationManagerCompat.from(this)) {
        // notificationId is a unique int for each notification that you must define
        notify(notificationId, builder.build())
    }
    

添加操作按钮

要添加操作按钮,请将 PendingIntent 传递给 addAction() 方法。这就像是设置通知的默认点按操作,不同的是不会启动 Activity,而是可以完成各种其他任务
例如启动在后台执行作业的 BroadcastReceiver,这样该操作就不会干扰已经打开的应用。

 val snoozeIntent = Intent(this, MyBroadcastReceiver::class.java).apply {
        action = ACTION_SNOOZE
        putExtra(EXTRA_NOTIFICATION_ID, 0)
    }
    val snoozePendingIntent: PendingIntent =
        PendingIntent.getBroadcast(this, 0, snoozeIntent, 0)
    val builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(pendingIntent)
            .addAction(R.drawable.ic_snooze, getString(R.string.snooze),
                    snoozePendingIntent)

添加直接回复操作

Android 7.0(API 级别 24)中引入的直接回复操作允许用户直接在通知中输入文本,然后会直接提交给应用
1、创建 RemoteInput.Builder 的实例以便您添加到通知操作

   // Key for the string that's delivered in the action's intent.
    private val KEY_TEXT_REPLY = "key_text_reply"
    var replyLabel: String = resources.getString(R.string.reply_label)
    var remoteInput: RemoteInput = RemoteInput.Builder(KEY_TEXT_REPLY).run {
        setLabel(replyLabel)
        build()
    }

2、为回复操作创建 PendingIntent

 // Build a PendingIntent for the reply action to trigger.
    var replyPendingIntent: PendingIntent =
        PendingIntent.getBroadcast(applicationContext,
            conversation.getConversationId(),
            getMessageReplyIntent(conversation.getConversationId()),
            PendingIntent.FLAG_UPDATE_CURRENT)

3、使用 addRemoteInput() 将 RemoteInput 对象附加到操作。

 // Create the reply action and add the remote input.
    var action: NotificationCompat.Action =
        NotificationCompat.Action.Builder(R.drawable.ic_reply_icon,
            getString(R.string.label), replyPendingIntent)
            .addRemoteInput(remoteInput)
            .build()
    

4、对通知应用操作并发出通知。

    // Build the notification and add the action.
    val newMessageNotification = Notification.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_message)
            .setContentTitle(getString(R.string.title))
            .setContentText(getString(R.string.content))
            .addAction(action)
            .build()

    // Issue the notification.
    with(NotificationManagerCompat.from(this)) {
        notificationManager.notify(notificationId, newMessageNotification)
    }

要从通知回复界面接收用户输入,请调用 RemoteInput.getResultsFromIntent() 并将 BroadcastReceiver 收到的 Intent 传递给它:

 private fun getMessageText(intent: Intent): CharSequence? {
        return RemoteInput.getResultsFromIntent(intent)?.getCharSequence(KEY_TEXT_REPLY)
    }

处理完文本后,必须使用相同的 ID 和标记(如果使用)调用 NotificationManagerCompat.notify() 来更新通知。若要隐藏直接回复界面并向用户确认他们的回复已收到并得到正确处理,则必须完成该操作。

   // Build a new notification, which informs the user that the system
    // handled their interaction with the previous notification.
    val repliedNotification = Notification.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_message)
            .setContentText(getString(R.string.replied))
            .build()

    // Issue the new notification.
    NotificationManagerCompat.from(this).apply {
        notificationManager.notify(notificationId, repliedNotification)
    }

在处理这个新通知时,请使用传递给接收者的 onReceive() 方法的上下文。

您还应通过调用 setRemoteInputHistory() 将回复附加到通知底部。但如果要构建消息应用,应创建消息式通知,并在会话中附加新消息。

有关来自消息应用的通知的更多建议,请参阅消息应用的最佳做法

添加进度条

image.png
通过调用 setProgress(max, progress, false) 使用指示器。
第一个参数是“完成”值(如 100);第二个参数是当前完成的进度,最后一个参数表明这是一个确定性进度条。

 val builder = NotificationCompat.Builder(this, CHANNEL_ID).apply {
        setContentTitle("Picture Download")
        setContentText("Download in progress")
        setSmallIcon(R.drawable.ic_notification)
        setPriority(NotificationCompat.PRIORITY_LOW
    }
    val PROGRESS_MAX = 100
    val PROGRESS_CURRENT = 0
    NotificationManagerCompat.from(this).apply {
        // Issue the initial notification with zero progress
        builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false)
        notify(notificationId, builder.build())

        // Do the job here that tracks the progress.
        // Usually, this should be in a
        // worker thread
        // To show progress, update PROGRESS_CURRENT and update the notification with:
        // builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false);
        // notificationManager.notify(notificationId, builder.build());

        // When done, update the notification one more time to remove the progress bar
        builder.setContentText("Download complete")
                .setProgress(0, 0, false)
        notify(notificationId, builder.build())
    }

操作结束时,progress 应等于 max。您可以在操作完成后仍保留显示进度条,也可以将其移除。要移除进度条,请调用 setProgress(0, 0, false)

要显示不确定性进度条(不指示完成百分比的进度条),请调用 setProgress(0, 0, true)
结果会产生一个与上述进度条样式相同的指示器,区别是这个进度条是一个持续动画,不指示完成情况。
在您调用 setProgress(0, 0, false) 之前,进度动画会一直运行,调用后系统会更新通知以移除 Activity 指示器。

设置系统范围的类别

如果您的通知属于 NotificationCompat 中定义的预定义通知类别之一
(例如 CATEGORY_ALARM、CATEGORY_REMINDER、CATEGORY_EVENT 或 CATEGORY_CALL),
您应通过将相应类别传递到 setCategory() 来进行声明。

  var builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setCategory(NotificationCompat.CATEGORY_MESSAGE)

显示紧急消息

注意:如果应用的目标平台是 Android 10(API 级别 29)或更高版本,必须在应用清单文件中请求 USE_FULL_SCREEN_INTENT 权限,以便系统启动与时效性通知关联的全屏 Activity。
以下代码段展示了如何将通知与全屏 Intent 关联:

    val fullScreenIntent = Intent(this, ImportantActivity::class.java)
    val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
        fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)

    var builder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setSmallIcon(R.drawable.notification_icon)
            .setContentTitle("My notification")
            .setContentText("Hello World!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setFullScreenIntent(fullScreenPendingIntent, true)

设置锁定屏幕公开范围

要控制锁定屏幕中通知的可见详情级别,请调用 setVisibility() 并指定以下值之一:

更新通知

要在发出此通知后对其进行更新,请再次调用 NotificationManagerCompat.notify(),并将之前使用的具有同一 ID 的通知传递给该方法。如果之前的通知已被关闭,则系统会创建一个新通知。

您可以选择性调用 setOnlyAlertOnce(),这样通知只会在通知首次出现时打断用户(通过声音、振动或视觉提示),而之后更新则不会再打断用户。

有关消息应用的最佳做法

从 Android 7.0(API 级别 24)起,Android 提供了专用于消息内容的通知样式模板。使用 NotificationCompat.MessagingStyle 类,您可以更改在通知中显示的多个标签,包括会话标题、其他消息和通知的内容视图。
以下代码段展示了如何使用 MessagingStyle 类自定义通知的样式。

    var notification = NotificationCompat.Builder(this, CHANNEL_ID)
            .setStyle(NotificationCompat.MessagingStyle("Me")
                    .setConversationTitle("Team lunch")
                    .addMessage("Hi", timestamp1, null) // Pass in null for user.
                    .addMessage("What's up?", timestamp2, "Coworker")
                    .addMessage("Not much", timestamp3, null)
                    .addMessage("How about lunch?", timestamp4, "Coworker"))
            .build()

从 Android 8.0(API 级别 26)起,使用 NotificationCompat.MessagingStyle 类的通知会在采用折叠形式时显示更多内容

5、权限 - 用于检查和请求应用权限的兼容性 API

6、偏好设置 - 创建交互式设置屏幕

**注意:**本指南介绍如何使用 AndroidX Preference Library。自 Android 10 开始,系统已弃用 android.preference 库平台。

创建层次结构

<PreferenceScreen
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <SwitchPreferenceCompat
        app:key="notifications"
        app:title="Enable message notifications"/>

    <Preference
        app:key="feedback"
        app:title="Send feedback"
        app:summary="Report technical issues or suggest new features"/>

</PreferenceScreen>

扩充层次结构

class MySettingsFragment : PreferenceFragmentCompat() {
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.preferences, rootKey)
    }
}

然后,与您对其他 Fragment 进行的操作一样,您可以将此 Fragment 添加到您的 Activity:

class MySettingsActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        supportFragmentManager
                .beginTransaction()
                .replace(R.id.settings_container, MySettingsFragment())
                .commit()
    }
}

7、共享 - 提供适合应用操作栏的共享操作

Android 应用的一大优点是它们能够互相通信和集成。如果某一功能并非应用的核心,而且已存在于另一个应用中,为何要重新开发它?

本节说明如何借助 Intent对象使用 Android Sharesheet 和 Intent Resolver 在不同应用之间发送和接收简单数据(如文本、图像和文件)的一些常用方法。

1、将简单的数据发送给其他应用

Android 为用户提供了两种在应用之间分享数据的方式:

  • Android Sharesheet 主要用于将内容发送到应用外部和/或直接发送给其他用户。例如,将网址分享给朋友。
  • Android intent 解析器最适合将数据传递到明确定义的任务的下一个阶段。例如,从应用中打开 PDF,并让用户挑选他们首选的查看器。

发送文本内容

    val sendIntent: Intent = Intent().apply {
        action = Intent.ACTION_SEND
        putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
        type = "text/plain"
    }

    val shareIntent = Intent.createChooser(sendIntent, null)
    startActivity(shareIntent)

发送二进制内容

 val shareIntent: Intent = Intent().apply {
        action = Intent.ACTION_SEND
        putExtra(Intent.EXTRA_STREAM, uriToImage)
        type = "image/jpeg"
    }
    startActivity(Intent.createChooser(shareIntent, resources.getText(R.string.send_to)))

使用正确的 MIME 类型

您应该为要发送的数据提供最具体的 MIME 类型。例如,分享纯文本时,应使用 text/plain。以下是在 Android 中发送简单数据时一些常用的 MIME 类型。

  • text/plain、text/rtf、text/html 和 text/json,接收方应注册 text/*
  • image/jpg、image/png 和 image/gif,接收方应注册 image/*
  • video/mp4 和 video/3gp,接收方应注册 video/*
  • application/pdf,接收方应注册支持的文件扩展名
  • 您可以使用 MIME 类型 /,但强烈建议您不要这样做,因为它仅与能够处理通用数据流的 Activity 匹配。
    Android Sharesheet 可能会根据提供的 MIME 类型显示内容预览。某些预览功能仅适用于特定类型。

分享多份内容

要分享多份内容,请将 ACTION_SEND_MULTIPLE 操作与指向该内容的一系列 URI 一起使用

    val imageUris: ArrayList<Uri> = arrayListOf(
            // Add your image URIs here
            imageUri1,
            imageUri2
    )

    val shareIntent = Intent().apply {
        action = Intent.ACTION_SEND_MULTIPLE
        putParcelableArrayListExtra(Intent.EXTRA_STREAM, imageUris)
        type = "image/*"
    }
    startActivity(Intent.createChooser(shareIntent, "Share images to.."))

向文本预览添加丰富的内容

从 Android 10(API 级别 29)开始,Android Sharesheet 可以显示分享的文本的预览。
如果要预览文本,您可以设置标题和/或缩略图。在调用 Intent.createChooser() 之前,先添加 Intent.EXTRA_TITLE 的说明。通过 ClipData 添加相关的缩略图。

     val share = Intent.createChooser(Intent().apply {
          action = Intent.ACTION_SEND
          putExtra(Intent.EXTRA_TEXT, "https://developer.android.com/training/sharing/")

          // (Optional) Here we're setting the title of the content
          putExtra(Intent.EXTRA_TITLE, "Introducing content previews")

          // (Optional) Here we're passing a content URI to an image to be displayed
          setClipData(contentUri);
          setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
      }, null)
      startActivity(share)

添加自定义目标

在调用 Intent.createChooser() 之后,向您的分享 intent 添加 Intent.EXTRA_CHOOSER_TARGETSIntent.EXTRA_INITIAL_INTENTS

val share = Intent.createChooser(myShareIntent, null).apply {
        putExtra(Intent.EXTRA_CHOOSER_TARGETS, myChooserTargetArray)
        putExtra(Intent.EXTRA_INITIAL_INTENTS, myInitialIntentArray)
    }

按组件排除特定目标

在调用 Intent.createChooser() 之后,向您的 intent 添加 Intent.EXTRA_EXCLUDE_COMPONENTS

  val share = Intent.createChooser(myShareIntent, null).apply {
      // Only use components you have control over
      share.putExtra(Intent.EXTRA_EXCLUDE_COMPONENTS, myComponentArray)
    }

获取有关分享的信息

   var share = new Intent(Intent.ACTION_SEND);
    ...
    val pi = PendingIntent.getBroadcast(myContext, requestCode, Intent(myContext, MyBroadcastReceiver.class),
    Intent.FLAG_UPDATE_CURRENT)
    share = Intent.createChooser(share, null, pi.intentSender);

然后,在 MyBroadcastReceiver 中接收回调,并查看 Intent.EXTRA_CHOSEN_COMPONENT

    override fun onReceive(context: Context, intent: Intent) {
      ...
      val clickedComponent : ComponentName = intent.getParcelableExtra(EXTRA_CHOSEN_COMPONENT);
    }
    

使用 Android intent 解析器

    val sendIntent: Intent = Intent().apply {
        action = Intent.ACTION_SEND
        putExtra(Intent.EXTRA_TEXT, "This is my text to send.")
        type = "text/plain"
    }
    startActivity(sendIntent)

2、从其他应用接收简单的数据

您的应用可以通过三种方式接收其他应用发送的数据:

  • 在清单中有匹配的 intent-filter 标记的 Activity
  • 由您的 ChooserTargetService 返回的一个或多个 ChooserTarget 对象
  • 您的应用发布的共享快捷方式。它们将取代 ChooserTarget 对象。只有当您的应用在 Android 10(API 级别 29)平台上运行时,才可以使用共享快捷方式。

支持 MIME 类型

您的应用应支持接收尽可能广泛的 MIME 类型。例如,用于发送文本、图像和视频的短信应用应支持接收 text/、image/ 和 video/*。以下是在 Android 中发送简单数据时常见的一些 MIME 类型。

text/,发送方通常会发送 text/plain、text/rtf、text/html、text/json
image/
,发送方通常会发送 image/jpg、image/png、image/gif
video/*,发送方通常会发送 video/mp4、video/3gp
接收方应注册受支持的文件扩展名,发送方通常会发送 application/pdf

通过 Activity 接收数据

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

处理传入的内容

要处理 Intent 传送的内容,请调用 getIntent() 以获取 Intent 对象

override fun onCreate(savedInstanceState: Bundle?) {
        ...
        when {
            intent?.action == Intent.ACTION_SEND -> {
                if ("text/plain" == intent.type) {
                    handleSendText(intent) // Handle text being sent
                } else if (intent.type?.startsWith("image/") == true) {
                    handleSendImage(intent) // Handle single image being sent
                }
            }
            intent?.action == Intent.ACTION_SEND_MULTIPLE
                    && intent.type?.startsWith("image/") == true -> {
                    handleSendMultipleImages(intent) // Handle multiple images being sent
            }
            else -> {
                // Handle other intents, such as being started from the home screen
            }
        }
        ...
    }

    private fun handleSendText(intent: Intent) {
        intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
            // Update UI to reflect text being shared
        }
    }

    private fun handleSendImage(intent: Intent) {
        (intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri)?.let {
            // Update UI to reflect image being shared
        }
    }

    private fun handleSendMultipleImages(intent: Intent) {
        intent.getParcelableArrayListExtra<Parcelable>(Intent.EXTRA_STREAM)?.let {
            // Update UI to reflect multiple images being shared
        }
    }
    

确保用户能够识别您的应用

从 Android 10(API 级别 29)开始,Android Sharesheet 将仅使用清单中的 application 标签上设置的图标。在 intent-filter 和 activity 标签上设置的图标将被忽略。

提供直接共享目标

直接共享于 Android 6.0(API 级别 23)中引入,支持应用通过 ChooserTargetService 提供 ChooserTarget 对象。在此机制下,系统会根据需要被动检索结果,从而造成目标加载缓慢。
在 Android 10(API 级别 29)中,新的 Sharing Shortcuts API 取代了 ChooserTargetService Direct Share API。
要查看发布共享快捷方式的示例,请参阅共享快捷方式代码示例

获得最佳排名

 val person = Person.Builder()
      ...
      .setName(fullName)
      .setKey(staticPersonIdentifier)
      .setUri("tel:$phoneNumber") // alternatively "mailto:$email" or CONTENT_LOOKUP_URI
      .build()

    val shortcutInfo = ShortcutInfoCompat.Builder(myContext, staticPersonIdentifier)
      ...
      .setShortLabel(firstName)
      .setLongLabel(fullName)
      .setPerson(person)
//通过调用 setLongLived(true)确保快捷方式长期存在。

      .setLongLived(true)
      .setRank(personRank)
      .build()
    
  val notif = NotificationCompat.Builder(myContext, channelId)
      ...
//确保所有 shortcutId 独一无二,且不在不同的目标上重复使用。
      .setShortcutId(staticPersonIdentifier)
      .build()

提供快捷方式图像

要制作共享快捷方式,您需要通过 setIcon() 添加图像。

声明共享目标

    <shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
      <share-target android:targetClass="com.example.android.sharingshortcuts.SendMessageActivity">
        <data android:mimeType="text/plain" />
        <category android:name="com.example.android.sharingshortcuts.category.TEXT_SHARE_TARGET" />
      </share-target>
    </shortcuts>

使用 AndroidX 提供共享快捷方式和 ChooserTarget

    <activity
        android:name=".SendMessageActivity"
        android:label="@string/app_name"
        android:theme="@style/SharingShortcutsDialogTheme">
        <!-- This activity can respond to Intents of type SEND -->
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
        <!-- Only needed if you import the sharetarget AndroidX library that
             provides backwards compatibility with the old DirectShare API.
             The activity that receives the Sharing Shortcut intent needs to be
             taken into account with this chooser target provider. -->
        <meta-data
            android:name="android.service.chooser.chooser_target_service"
            android:value="androidx.sharetarget.ChooserTargetServiceCompat" />
    </activity>

8、切片 - 创建可在应用外部显示应用数据的灵活界面元素

Android Jetpack 内置了对切片的支持,并且可以向后一直扩展到 Android 4.4,覆盖约 95% 的 Android 用户。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章