问题描述
我有一个要求通过share Intent发送一个apk文件,我也没有任何麻烦地实现了.但问题仅在通过 GMail 发送 apk 时出现,我在尝试附加时收到 permission denied.我真的不知道 GMail 发生了什么.请通过您的答案和解决方案帮助我.任何小提示和技巧也对我有用.提前致谢
I have a requirement to send a apk file through share Intent and I have also implemented without any hassle. But the problem arises only while sending apk via GMail, I am getting permission denied while i try to attach. I really dont know what is happening with GMail. Kindly help me through your answers and solutions. Any Small hint and tips would also be useful for me. Thanks in advance
我正在使用以下代码通过共享意图发送 APK:
public static void appSend(ArrayList<File> files,Context context){
Intent shareIntent = new Intent(Intent.ACTION_SEND_MULTIPLE);
shareIntent.setType("application/vnd.android.package-archive");
shareIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
ArrayList<Uri> uriFiles = new ArrayList<Uri> ();
for(File file: files) {
uriFiles.add (Uri.fromFile (file));
}
shareIntent.putParcelableArrayListExtra (Intent.EXTRA_STREAM, uriFiles);
try {
context.startActivity (Intent.createChooser (shareIntent, "Share via"));
} catch (android.content.ActivityNotFoundException ex) {
Toast.makeText (context, "There are no share applications installed.", Toast.LENGTH_SHORT).show();
}
}
Androidmanifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.sample.share"
android:versionCode="2"
android:versionName="1.1">
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="ANDROID.PERMISSION.READ_EXTERNAL_STORAGE"/>
<uses-feature
android:glEsVersion="0x00020000"
android:required="true" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name">
<activity
android:name="com.sample.share.SplashActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.sample.share.LandingScreenActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar.FullScreen"/>
<activity
android:name="com.sample.share.MainActivity"
android:label="@string/app_name"
android:theme="@style/ShareToolbar"/>
</application>
</manifest>
用于获取设备中存在的应用列表的适配器类
ShowAppsAdapter.java
public class ShowAppsAdapter extends RecyclerView.Adapter<ShowAppsAdapter.ViewHolder> implements Filterable{
private Context context;
private static List pkgAppsList;
private List pkgAppsListOriginal;
private int mLayout;
private ArrayList<File> mFileList;
static OnItemClickListener mItemClickListener;
private ItemFilter filter = new ItemFilter();
private HashMap<String,Boolean> itemChecked = new HashMap<String,Boolean>();
private Typeface tf;
public ShowAppsAdapter(Context context, List pkgAppsList, int layout, Typeface tf) {
this.context = context;
this.pkgAppsList = pkgAppsList;
this.pkgAppsListOriginal = pkgAppsList;
this.mLayout = layout;
this.mFileList = new ArrayList<File> ();
this.tf = tf;
for (int i = 0; i < this.getItemCount (); i++) {
itemChecked.put ((String) ((ResolveInfo) pkgAppsList.get (i)).loadLabel (context.getPackageManager ()), false); // initializes all items value with false
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
View v = LayoutInflater.from(viewGroup.getContext()).inflate(mLayout, viewGroup, false);
return new ViewHolder(v);
}
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
final ResolveInfo info = (ResolveInfo) pkgAppsList.get(position);
final File file = new File(info.activityInfo.applicationInfo.publicSourceDir);
String appSize= (Utils.getFileSize(context, info.activityInfo.applicationInfo.sourceDir));
holder.txtAppName.setText(info.loadLabel(context.getPackageManager()));
holder.txtAppSize.setText(/*info.activityInfo.packageName*/""+appSize);
holder.txtAppName.setTypeface(tf);
holder.txtAppSize.setTypeface(tf);
holder.txtAppIcon.setImageDrawable(info.loadIcon(context.getPackageManager()));
holder.chkTick.setChecked(itemChecked.get(info.loadLabel (context.getPackageManager ())));
holder.chkTick.setOnClickListener (new View.OnClickListener () {
@Override
public void onClick (View view) {
toggleSelected((String) info.loadLabel (context.getPackageManager ()), holder.chkTick.isChecked(), file);
}
});
}
private void toggleSelected (String name, boolean b, File file) {
itemChecked.put (name,b);
if(b){
addAppList(file);
}else{
removeAppList(file);
}
}
private void addAppList (File file) {
mFileList.add (file);
}
private void removeAppList (File file) {
mFileList.remove (file);
}
public ArrayList<File> getAppList(){
return mFileList;
}
@Override
public int getItemCount() {
return pkgAppsList == null ? 0 : pkgAppsList.size();
}
@Override
public Filter getFilter () {
return filter;
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView txtAppName;
TextView txtAppSize;
ImageView txtAppIcon;
CheckBox chkTick;
public ViewHolder(View itemView) {
super(itemView);
txtAppName = (TextView)itemView.findViewById(R.id.text_app_name);
txtAppSize = (TextView)itemView.findViewById(R.id.txt_app_size);
txtAppIcon = (ImageView)itemView.findViewById(R.id.img_app_icon);
chkTick = (CheckBox)itemView.findViewById (R.id.chk_tick);
itemView.setOnClickListener(this);
}
@Override
public void onClick(View v) {
mItemClickListener.onItemClick(v, getAdapterPosition (),((ResolveInfo)pkgAppsList.get (getAdapterPosition ()))); //OnItemClickListener mItemClickListener;
}
}
public interface OnItemClickListener {
public void onItemClick (View view, int position, ResolveInfo o);
}
public void SetOnItemClickListener(final OnItemClickListener mItemClickListener) {
this.mItemClickListener = mItemClickListener;
}
@Override
public long getItemId(int i) {
return i;
}
private class ItemFilter extends Filter{
@Override
protected FilterResults performFiltering (CharSequence charSequence) {
String searchString = charSequence.toString ().toLowerCase ();
FilterResults results = new FilterResults();
final List list = pkgAppsListOriginal;
int count = list.size();
final List nlist = new ArrayList<ResolveInfo>(count);
String filterableString ;
for (int i = 0; i < count; i++) {
final ResolveInfo info = (ResolveInfo) pkgAppsListOriginal.get(i);
filterableString = (String) info.loadLabel (context.getPackageManager ());
if (filterableString.toLowerCase().contains(searchString)) {
nlist.add(pkgAppsListOriginal.get (i));
}
}
results.values = nlist;
results.count = nlist.size();
return results;
}
@Override
protected void publishResults (CharSequence charSequence, FilterResults filterResults) {
pkgAppsList = (List) filterResults.values;
notifyDataSetChanged ();
}
}
}
推荐答案
在应用程序之间共享文件时,应该使用 FileProvider 根据 设置文件共享培训,因为这样可以确保接收应用无需任何权限即可读取文件.从 Android 6.0 开始,Gmail 不再请求存储权限,这意味着它无法读取您使用 Uri.fromFile()
提供的任何文件.
When sharing files between applications, you should use a FileProvider as per the setting up file sharing training as this ensures that the receiving app can read the file without requiring any permissions. As of Android 6.0, Gmail does not request the storage permission, meaning it is unable to read any files you provide with Uri.fromFile()
.
您将在清单中声明一个 FileProvider
:
You'd declare a FileProvider
in your manifest:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
一个 XML 文件(在本例中称为 filepaths.xml
以匹配上述清单声明),它确定哪些目录可通过 FileProvider
获得:
An XML file (in this case called filepaths.xml
to match the above manifest declaration) which determines which directories are available via the FileProvider
:
<paths>
<files-path path="images/" name="myimages" />
</paths>
然后,使用 ,传递与清单相同的权限.
Then, in place of using Uri.fromFile(file)
, you use FileProvider.getUriForFile()
, passing in the same authority as in your manifest.
这篇关于使用 GMail app android 附加 apk 文件时权限被拒绝的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!