compose调用系统分享功能分享图片文件

compose调用系统分享功能图片文件

  • 简介
    • UI界面
    • 提供给外部程序的文件访问权限
      • 创建FileProvider
      • 设置共享文件夹
  • 通用分享工具
  • 虚拟机验证结果
  • 参考

本系列用于新人安卓基础入门学习笔记,有任何不同的见解欢迎留言

运行环境 jdk17 andriod 34 compose material3

简介

本案例采用 provider来分享当前应用下的文件,其他系统文件直接通过context地址直接获取
本案例是直接 【MediaProvider】content://media/external/images/media,来让其他app直接访问,如果是系统文件请直接忽略provider相关设置

在这里插入图片描述

UI界面

在这里插入图片描述

package com.example.myapplication.uiimport android.app.Activity
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Delete
import androidx.compose.material.icons.filled.Edit
import androidx.compose.material.icons.filled.MoreVert
import androidx.compose.material.icons.filled.Share
import androidx.compose.material3.BottomAppBar
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavHostController
import com.example.myapplication.R
import com.example.myapplication.common.ShareUtil
import com.example.myapplication.common.Utils
import com.example.myapplication.common.ui.FullScreenImage
import com.example.myapplication.entity.ImageEntity
import java.io.Filevar snackbarHostState = SnackbarHostState()@Composable
fun ImageDetail(imageEntity: ImageEntity, mainController: NavHostController) {Scaffold(snackbarHost = {SnackbarHost(hostState = snackbarHostState, modifier = Modifier.padding(0.dp))},topBar = {ImageTopBar(imageEntity.name, mainController)},bottomBar = {GetBottomBar(imageEntity.file)}) { innerPadding ->FullScreenImage(imageEntity = imageEntity, modifier = Modifier.padding(innerPadding))}
}@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun GetBottomBar(file: File) {val scope = rememberCoroutineScope()val activity = LocalContext.current as ActivityBottomAppBar(containerColor = MaterialTheme.colorScheme.primaryContainer,contentColor = MaterialTheme.colorScheme.primary,) {Row(Modifier.fillMaxWidth(),horizontalArrangement = Arrangement.SpaceEvenly,verticalAlignment = Alignment.CenterVertically) {val buttonModifier = Modifier.size(70.dp)val IconModifier = Modifier.size(30.dp)val message = stringResource(id = R.string.empty_ui)IconButton(onClick = { Utils.message(scope, message, snackbarHostState) },modifier = buttonModifier) {Column(horizontalAlignment = Alignment.CenterHorizontally) {Icon(modifier = IconModifier,imageVector = Icons.Filled.Edit,contentDescription = "Localized description")Text(text = "编辑",fontSize = 12.sp,)}}IconButton(onClick = {// 打开系统分享ShareUtil.shareImage(activity,"com.example.myapplication.fileprovider",file.name,file.path)},modifier = buttonModifier) {Column(horizontalAlignment = Alignment.CenterHorizontally) {Icon(modifier = IconModifier,imageVector = Icons.Filled.Share,contentDescription = "Localized description")Text(text = "分享", fontSize = 12.sp)}}IconButton(onClick = { Utils.message(scope, message, snackbarHostState) },modifier = buttonModifier) {Column(horizontalAlignment = Alignment.CenterHorizontally) {Icon(modifier = IconModifier,imageVector = Icons.Filled.Delete,contentDescription = "Localized description")Text(text = "删除", fontSize = 12.sp)}}IconButton(onClick = { Utils.message(scope, message, snackbarHostState) },modifier = buttonModifier) {Column(horizontalAlignment = Alignment.CenterHorizontally) {Icon(modifier = IconModifier,imageVector = Icons.Filled.MoreVert,contentDescription = "Localized description")Text(text = "更多", fontSize = 12.sp)}}}}}
}

提供给外部程序的文件访问权限

  • 这里只适用于外部访问当前app下的数据,本案例是直接 content://media/external/images/media,来让其他app直接访问,如果是系统文件请直接忽略这一段
  • Android 7.0之前,文件的Uri以file:///形式提供给其他app访问。
  • Android 7.0之后,分享文件的Uri发生了变化。为了安全起见,file:///形式的Uri不能正常访问。官方提供了FileProvider,FileProvider生成的Uri会以content://的形式分享给其他app使用。
    content形式的Uri可以让其他app临时获得读取(Read)和写入(Write)权限,只要我们在创建Intent时,使用Intent.setFlags()添加权限。只要接收Uri的app在接收的Activity任务栈中处于活动状态,添加的权限就会一直有效,直到app被任务栈移除

创建FileProvider

<application>
....<providerandroid:name="androidx.core.content.FileProvider"android:authorities="com.example.myapplication.fileprovider"android:exported="false"android:grantUriPermissions="true"><meta-dataandroid:name="android.support.FILE_PROVIDER_PATHS"android:resource="@xml/filepath" /> </provider>
</application>
  • android:authorities 指定可以查找此内容提供程序的权限。可以使用分号分隔多个授权机构。授权机构名称应该使用java风格的命名约定(如com.google.provider.MyProvider),以避免冲突。通常,此名称与描述提供程序数据结构的类实现相同。
  • android:resource 文件的权限清单
  • android:exported 设置为false,FileProvider不需要公开。
  • android:grantUriPermissions 设置为true,这样就能授权接收端的app临时访问权限了。

设置共享文件夹

这里的绝对路径是 /data/data/{package}
例如我的是 /data/data/com.example.myapplication

在res/xml中创建一个资源文件filepath.xml

<?xml version="1.0" encoding="utf-8"?>
<paths><files-path name="Pictures" path="/pictures/"/>
</paths>

/data/data/com.example.myapplication/files/pictures/

通用分享工具

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;import androidx.core.content.FileProvider;import java.io.File;public class ShareUtil {// 原生通用分享文本public static void shareText(Activity activity, String title, String text) {Intent sendIntent = new Intent();sendIntent.setAction(Intent.ACTION_SEND);sendIntent.putExtra(Intent.EXTRA_TEXT, text);sendIntent.setType("text/plain");activity.startActivityForResult(Intent.createChooser(sendIntent, title), 80001);}// 原生通用分享图片public static void shareImage(Activity activity, String authority, String title, File file){shareImage(activity, authority, title, file, false);}public static void shareImage(Activity activity, String authority, String title, File file,  boolean isApp) {Intent sendIntent = new Intent();sendIntent.setAction(Intent.ACTION_SEND);Uri uri = getFileUri(activity, authority, file, isApp);sendIntent.putExtra(Intent.EXTRA_STREAM, uri);sendIntent.setType("image/png");activity.startActivityForResult(Intent.createChooser(sendIntent, title), 80002);}// 通用文件public static void shareFile(Activity activity, String authority, String type, File file,  boolean isApp) {Intent sendIntent = new Intent();sendIntent.setAction(Intent.ACTION_SEND);Uri uri = FileProvider.getUriForFile(activity, authority , file);sendIntent.putExtra(Intent.EXTRA_STREAM, uri);sendIntent.setType(type);activity.startActivityForResult(Intent.createChooser(sendIntent, file.getName()), 80002);}public static Uri getFileUri(Context context, String authority, File file, boolean isApp) {Uri uri;// 低版本直接用 Uri.fromFileif (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {uri = Uri.fromFile(file);} else {if(isApp){// 分享当前应用下的共享路径中的uri = FileProvider.getUriForFile(context, authority , file);}else {// 分享外部的文件uri = getImageContentUri(context, file);}}return uri;}public static Uri getImageContentUri(Context context, File imageFile) {String filePath = imageFile.getAbsolutePath();Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "=? ",new String[]{filePath}, null);if (cursor != null && cursor.moveToFirst()) {@SuppressLint("Range") int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));Uri baseUri = Uri.parse("content://media/external/images/media");return Uri.withAppendedPath(baseUri, "" + id);} else {if (imageFile.exists()) {ContentValues values = new ContentValues();values.put(MediaStore.Images.Media.DATA, filePath);return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);} else {return null;}}}
}

虚拟机验证结果

在这里插入图片描述
在这里插入图片描述

参考

Android之FileProvider详解 - 掘金 (juejin.cn)
Android原生分享与指定app分享_android 原生分享链接-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/319740.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

线性数据结构-手写队列-哈希(散列)Hash

什么是hash散列&#xff1f; 哈希表的存在是为了解决能通过O(1)时间复杂度直接索引到指定元素。这是什么意思呢&#xff1f;通过我们使用数组存放元素&#xff0c;都是按照顺序存放的&#xff0c;当需要获取某个元素的时候&#xff0c;则需要对数组进行遍历&#xff0c;获取到指…

ton-http-api安装部署

1、拉取github代码 mkdir /data git clone https://github.com/toncenter/ton-http-api.git cd ton-http-api2、创建环境变量 ./configure.py cat .env TON_API_CACHE_ENABLED0 TON_API_CACHE_REDIS_ENDPOINTcache_redis TON_API_CACHE_REDIS_PORT6379 TON_API_CACHE_REDIS_T…

6.k8s中的secrets资源

一、Secret secrets资源&#xff0c;类似于configmap资源&#xff0c;只是secrets资源是用来传递重要的信息的&#xff1b; secret资源就是将value的值使用base64编译后传输&#xff0c;当pod引用secret后&#xff0c;k8s会自动将其base64的编码&#xff0c;反编译回正常的字符…

仿知乎网站问答源码,开源版

仿知乎网站问答源码&#xff0c;开源版 需要一定动手能力 发文章&#xff0c;发视频&#xff0c;发想法&#xff0c;提问回答&#xff0c;注册登录 开发环境 使用技术&#xff1a;springbootthymeleafRedis&#xff1b; 开发环境&#xff1a;tomcat8.0&#xff0c;jdk8.0, ID…

2023下半年软件设计师上午题——冒泡排序

快速排除法&#xff0c;根据冒泡排序特性&#xff0c;每一趟排序都会确实最大/最小值&#xff0c;故升序两趟后&#xff0c;最后两个元素应该是已经排序好的第二大&#xff0c;和最大的元素&#xff0c;所以排除B,D&#xff0c;再因为每次排序都会两两交换&#xff0c;所以排除…

裸金属服务器,云用户的新体验

定义 裸金属服务器&#xff08;Bare Metal Server&#xff09;&#xff0c;是一台既具有传统物理服务器特点的硬件设备&#xff0c;又具备云计算技术的虚拟化服务功能&#xff0c;是硬件和软件优势结合的产物。可以为企业提供专属的云上物理服务器&#xff0c;为核心数据库、关…

【010】基于springboot+vue的校园资产管理

【010】基于springbootvue的校园资产管理 一、系统情况介绍 该系统是基于springbootvue的校园资产管理系统&#xff0c;校园资产管理是一款可以真正提升管理者的办公效率的软件系统。主要有以下功能&#xff1a;个人信息管理、校园资产管理、资产借用管理、入库管理、用户管理…

[Java EE] 多线程(六):线程池与定时器

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏:&#x1f355; Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 &#x1f9c0;Java …

利用大语言模型(KIMI)构建智能产品的信息模型

数字化的核心是数字化建模&#xff0c;为一个事物构建数字模型是一件非常繁杂和耗费人工的事情。利用大语言模型&#xff0c;能够轻松地生成设备的信息模型&#xff0c;我们的初步实验表明&#xff0c;只要提供足够的模板&#xff0c;就能够准确地生成设备的数字化模型。 我们尝…

【CV-CUDA实战】使用Python+TensorRT+CVCUDA优化YOLOv8

目录 什么是CV-CUDA环境准备准备CV-CUDA静态库解压添加至变量将PyBind静态库复制到env下算子设计前处理算子 TensorRT模型加载后处理函数 完整代码输出演示为什么重新写了&#xff1f;结语 什么是CV-CUDA NVIDIA CV-CUDA™ 是一个开源项目&#xff0c;用于构建云规模人工智能 (…

cefsharp实现资源替换如网页背景、移除替换标签、html标识、执行javascript脚本学习笔记(含源码说明)

(一)实现测试(仅供学习参考) 1.1 目标系统页面(登录页)和登录后首页面中2处(一个替换一个移除) 1.2 实现后效果(使用cefsharp自定义浏览器实现以上功能) 1.3 登录后页面替换和移除 系统名称和一个功能菜单li (二)通过分析代码实现脚本编写 2.1 分开处理,设置了…

STM32中断之TIM定时器详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. TIM简述 2. 定时器类型 2.1 基本定时器 2.2 通用定时器 2.3 高级定时器 3. 定时中断 4. 代码示例1 5. 代码示例2 1. TIM简述 定时器的基本功能&#xff1a;定时器可以在预定的时间间隔内产生周…

网络安全之弱口令与命令爆破(中篇)(技术进阶)

目录 一&#xff0c;什么是弱口令&#xff1f; 二&#xff0c;为什么会产生弱口令呢&#xff1f; 三&#xff0c;字典的生成 四&#xff0c;使用Burpsuite工具验证码爆破 总结 笔记改错 一&#xff0c;什么是弱口令&#xff1f; 弱口令就是容易被人们所能猜到的密码呗&a…

基于LLama3、Langchain,Chroma 构建RAG

概要&#xff1a; 使用Llama3 Langchain和ChromaDB创建一个检索增强生成&#xff08;RAG&#xff09;系统。这将允许我们询问有关我们的文档&#xff08;未包含在训练数据中&#xff09;的问题&#xff0c;而无需对大型语言模型&#xff08;LLM&#xff09;进行微调。在使用RA…

mysql 指定根目录 迁移根目录

mysql 指定根目录 迁移根目录 1、问题描述2、问题分析3、解决方法3.1、初始化mysql前就手动指定mysql根目录为一个大的分区(支持动态扩容)&#xff0c;事前就根本上解决mysql根目录空间不够问题3.1.0、方法思路3.1.1、卸载mariadb3.1.2、下载Mysql安装包3.1.3、安装Mysql 8.353…

jupyter notebook使用与本地位置设置

本地安装好Anaconda之后&#xff0c;自带的有Jupter notebook。 使用jupyter notebook 使用jupyter notebook时&#xff0c;可以直接打开或者搜索打开&#xff1a; 打开后&#xff0c;我们生成的或者编辑的一些文件&#xff0c;都可以看到&#xff0c;如下&#xff1a; j…

学习STM32第二十天

低功耗编程 一、修改主频 STM32F4xx系列主频为168MHz&#xff0c;当板载8MHz晶振时&#xff0c;系统时钟HCLK满足公式 H C L K H S E P L L N P L L M P L L P HCLK \frac{HSE \times PLLN}{PLLM \times PLLP} HCLKPLLMPLLPHSEPLLN​&#xff0c;在文件stm32f4xx.h中可修…

uniapp 自定义相机插件(组件版、缩放、裁剪)组件 Ba-CameraView

自定义相机插件&#xff08;组件版、缩放、裁剪&#xff09; Ba-CameraView 简介&#xff08;下载地址&#xff09; Ba-CameraView 是一款自定义相机拍照组件&#xff0c;支持任意界面&#xff0c;支持裁剪 支持任意自定义界面支持手势缩放支持裁剪&#xff08;手势拖动、比…

R语言中,查看经安装的包,查看已经加载的包,查看特定包是否已经安装,安装包,更新包,卸载包

创建于&#xff1a;2024.5.4 R语言中&#xff0c;查看经安装的包&#xff0c;查看已经加载的包&#xff0c;查看特定包是否已经安装&#xff0c;安装包&#xff0c;更新包&#xff0c;卸载包 文章目录 1. 查看经安装的包2. 查看已经加载的包3. 查看特定包是否已经安装4. 安装包…

【Cpp】类和对象#拷贝构造 赋值重载

标题&#xff1a;【Cpp】类和对象#拷贝构造 赋值重载 水墨不写bug 目录 &#xff08;一&#xff09;拷贝构造 &#xff08;二&#xff09;赋值重载 &#xff08;三&#xff09;浅拷贝与深拷贝 正文开始&#xff1a; &#xff08;一&#xff09;拷贝构造 拷贝构造函数&…