我正在制作一个 APK 安装应用程序,并且经历了很多。特别是版本控制。为此,我查阅了一些帖子和 StackOverFlow。但现在所有的帖子让我更加困惑。那么,什么是正确的方法呢?
首先,请检查我下面关于每个版本安装的代码。让我们谈谈什么是正确的方法。
KitKat(API 19)、棒棒糖(API 21)、MashMellow(API 23)
fun installApkBelowNougat(apkFile: File) {
val apkUri = Uri.fromFile(apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,所有解决方案都是相同的,我们必须使用Uri.fromFile(file)来获得Uri.
牛轧糖(API 24)
fun installApkInNougat(apkFile: File) {
val apkUri = FileProvider.getUriForFile(applicationContext, applicationContext.packageName + ".fileProvider", apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,我们就不能再使用了Uri.fromFile(file)。因此,我们必须使用FileProvider“Nougat”来代替它。并且我们还必须<proivder/>在AndroidManifest.xml中这样写。
...
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS" …Run Code Online (Sandbox Code Playgroud) 我收到以下错误:
05-29 01:08:02.924: E/AndroidRuntime(5447): FATAL EXCEPTION: IntentService[com.sample.muzeitest.MuzeiClass]
05-29 01:08:02.924: E/AndroidRuntime(5447): java.lang.IllegalArgumentException: Failed to find configured root that contains /data/data/com.sample.muzeitest/files/wallpaper0.png
05-29 01:08:02.924: E/AndroidRuntime(5447): at android.support.v4.content.FileProvider$SimplePathStrategy.getUriForFile(FileProvider.java:678)
05-29 01:08:02.924: E/AndroidRuntime(5447): at android.support.v4.content.FileProvider.getUriForFile(FileProvider.java:377)
05-29 01:08:02.924: E/AndroidRuntime(5447): at com.sample.muzeitest.MuzeiClass.muzeiContentUri(MuzeiClass.java:58)
05-29 01:08:02.924: E/AndroidRuntime(5447): at com.sample.muzeitest.MuzeiClass.onUpdate(MuzeiClass.java:37)
05-29 01:08:02.924: E/AndroidRuntime(5447): at com.google.android.apps.muzei.api.MuzeiArtSource.processAndDispatchSubscriberAdded(MuzeiArtSource.java:614)
05-29 01:08:02.924: E/AndroidRuntime(5447): at com.google.android.apps.muzei.api.MuzeiArtSource.processSubscribe(MuzeiArtSource.java:581)
05-29 01:08:02.924: E/AndroidRuntime(5447): at com.google.android.apps.muzei.api.MuzeiArtSource.onHandleIntent(MuzeiArtSource.java:539)
05-29 01:08:02.924: E/AndroidRuntime(5447): at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)
05-29 01:08:02.924: E/AndroidRuntime(5447): at android.os.Handler.dispatchMessage(Handler.java:99)
05-29 01:08:02.924: E/AndroidRuntime(5447): at android.os.Looper.loop(Looper.java:137)
05-29 01:08:02.924: E/AndroidRuntime(5447): at android.os.HandlerThread.run(HandlerThread.java:61)
Run Code Online (Sandbox Code Playgroud)
当我尝试使用FileProvidermuzei app时.
我正在进行一项活动(从可绘制文件夹中添加一些位图/data/data/APP-SPACE-HERE/files/ …
我正在使用FileProvider在Android Nougat上拍照,这是我的代码
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.mypackage.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Run Code Online (Sandbox Code Playgroud)
file_paths.xml:
<paths>
<files-path name="img" path="images/" />
</paths>
Run Code Online (Sandbox Code Playgroud)
Java的:
String fileName = "cameraOutput" + System.currentTimeMillis() + ".jpg";
File imagePath = new File(getContext().getFilesDir(), "images");
File file = new File(imagePath, fileName);
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
final Uri outputUri = FileProvider.getUriForFile(activity, "com.mypackage.fileprovider", file);
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri);
getContext().grantUriPermission(
"com.google.android.GoogleCamera",
outputUri,
Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION
);
cameraIntent.setFlags(FLAG_GRANT_WRITE_URI_PERMISSION);
activity.startActivityForResult(cameraIntent, ACTIVITY_REQUEST_CODE);
Run Code Online (Sandbox Code Playgroud)
相机活动开始,成功拍照,但活动结果不正常,我在错误日志中看到的唯一的事情是
CAM_StateSavePic:将结果保存到URI时发生异常:Optional.of(content://com.mypackage.fileprovider/img/cameraOutput1469383289530.jpg)FileNotFoundException:是一个目录
编辑 错过了File#createNewFile();
我正在更改我的应用程序代码以支持Android 7,但在我的NotificationCompat.Builder.setSound(Uri)中传递来自FileProvider的Uri,Notification不播放任何声音,在Android 6中使用Uri.fromFile()正常工作.
mp3文件位于:
/Animeflv/cache/.sounds/
这是我的通知代码:
knf.animeflv.RequestBackground
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_not_r)
.setContentTitle(NotTit)
.setContentText(mess);
...
mBuilder.setVibrate(new long[]{100, 200, 100, 500});
mBuilder.setSound(UtilSound.getSoundUri(not)); //int
Run Code Online (Sandbox Code Playgroud)
这是我的UtilSound.getSoundUri(int)
public static Uri getSoundUri(int not) {
switch (not) {
case 0:
return RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
default:
try {
File file=new File(Environment.getExternalStorageDirectory()+"/Animeflv/cache/.sounds",getSoundsFileName(not));
if (file.exists()) {
file.setReadable(true,false);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
return FileProvider.getUriForFile(context, "knf.animeflv.RequestsBackground",file);
}else {
return Uri.fromFile(file);
}
}else {
Log.d("Sound Uri","Not found");
return getSoundUri(0);
}
}catch (Exception e){
e.printStackTrace();
return getSoundUri(0);
}
}
}
Run Code Online (Sandbox Code Playgroud)
在AndroidManifest.xml中:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="knf.animeflv.RequestsBackground"
android:exported="false"
android:grantUriPermissions="true"> …Run Code Online (Sandbox Code Playgroud) java android android-studio android-fileprovider android-7.0-nougat
到目前为止,使用此意图有一种简单的方法来安装APK文件:
final Intent intent=new Intent(Intent.ACTION_VIEW)
.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
Run Code Online (Sandbox Code Playgroud)
但是,如果你的应用程序中的Android API 24以上(牛轧糖- 7.0),你就可以或更新运行这段代码,你会得到一个异常,如图所示这里,例如:
android.os.FileUriExposedException: file:///storage/emulated/0/sample.apk exposed beyond app through Intent.getData()
Run Code Online (Sandbox Code Playgroud)
所以我做了我被告知的事情:使用支持库的FileProvider类,如下:
final Intent intent = new Intent(Intent.ACTION_VIEW)//
.setDataAndType(android.support.v4.content.FileProvider.getUriForFile(context,
context.getPackageName() + ".provider", apkFile),
"application/vnd.android.package-archive").addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Run Code Online (Sandbox Code Playgroud)
清单:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
Run Code Online (Sandbox Code Playgroud)
res/xml/provider_paths.xml:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!--<external-path name="external_files" path="."/>-->
<external-path
name="files_root"
path="Android/data/${applicationId}"/>
<external-path
name="external_storage_root"
path="."/>
</paths>
Run Code Online (Sandbox Code Playgroud)
但是,现在它仅适用于Android Nougat.在Android 5.0上,它抛出一个异常:ActivityNotFoundException.
我可以添加一个Android OS版本的检查,并使用任何一种方法,但正如我所读,应该使用一种方法:FileProvider.
所以,我尝试使用我自己的ContentProvider充当FileProvider,但我得到了与支持库的FileProvider相同的异常.
这是我的代码:
final Intent intent = new Intent(Intent.ACTION_VIEW)
.setDataAndType(OpenFileProvider.prepareSingleFileProviderFile(apkFilePath),
"application/vnd.android.package-archive")
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Run Code Online (Sandbox Code Playgroud)
OpenFileProvider.java …
android android-intent apk android-fileprovider android-7.0-nougat
我正在尝试通过instagram意图共享文件,但我意识到在API 24 ++上,我不能在未经许可的情况下仅将URI共享给其他应用。
按照此https://inthecheesefactory.com/blog/how-to-share-access-to-file-with-fileprovider-on-android-nougat/zh-CN教程,我已经设置了提供程序并提供了这样的路径:
表现
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="myapplication.file_provider"
android:exported="false"
android:grantUriPermissions="true"
tools:node="replace">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
Run Code Online (Sandbox Code Playgroud)
注意:有`tools:node = replace“来覆盖库RxPaparazzo中的提供者。
provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="my_images" path="files/"/>
</paths>
Run Code Online (Sandbox Code Playgroud)
保存位图并获取uri的代码
public static Uri savePicture(Context context, Bitmap bitmap) {
int cropHeight;
if (bitmap.getHeight() > bitmap.getWidth()) cropHeight = bitmap.getWidth();
else cropHeight = bitmap.getHeight();
bitmap = ThumbnailUtils.extractThumbnail(bitmap, cropHeight, cropHeight, ThumbnailUtils.OPTIONS_RECYCLE_INPUT);
File mediaStorageDir = new File(
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),
context.getString(R.string.app_name)
);
if (!mediaStorageDir.exists()) {
if (!mediaStorageDir.mkdirs()) {
return null;
}
}
String timeStamp = new …Run Code Online (Sandbox Code Playgroud) 我试图通过摆脱FileUriExposedException来支持Nougat.当我使用Uri.fromFile(gettheImageFilehere())方法我成功获取图像路径文件:///storage/emulated/0/DCIM/Camera/IMG_20170308_171951.jpg
当我使用
FileProvider.getUriForFile(HomeView.this, getApplicationContext().getPackageName() + ".provider",
gettheImageFilehere());
Run Code Online (Sandbox Code Playgroud)
我得到的图像路径为:/external_files/DCIM/Camera/IMG_20170308_171951.jpg
我试图使用android.os.FileUriExposedException上提供的实现. 这是我在androidmanifest.xml 里面的代码,我添加了提供程序:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
Run Code Online (Sandbox Code Playgroud)
然后我在res/xml文件夹中创建了provider_paths.xml,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_files" path="."/>
</paths>
Run Code Online (Sandbox Code Playgroud)
我对上述情况表示怀疑:
我得到的完整错误是无法解码流:java.io.FileNotFoundException:/ external_files/DCIM/Camera/IMG_20170308_175833.jpg(没有这样的文件或目录)
代码段的.java文件是在这里查看我的实现.
我所看到的一切都说你需要<provider>在AndroidManifest中添加一个部分,你需要引用一个XML资源文件来说明你想要的图像外部文件路径.
我正在做的不是那些,但我找到的代码片段正在工作,即使在Nougat和更新.
我想知道为什么.我无法弄清楚是什么导致这实际上起作用.
这是我的Android清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.inthecheesefactory.lab.intent_fileprovider">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Run Code Online (Sandbox Code Playgroud)
这是完整的MainActivity.我很乐意为你们减少它们但是我想确保我不会意外地削减你们需要看到的东西.我无法弄清楚.
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static final int REQUEST_TAKE_PHOTO = 1;
Button btnTakePhoto;
ImageView ivPreview;
String mCurrentPhotoPath;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initInstances();
}
private void initInstances() {
btnTakePhoto = (Button) findViewById(R.id.btnTakePhoto);
ivPreview = (ImageView) findViewById(R.id.ivPreview);
btnTakePhoto.setOnClickListener(this);
} …Run Code Online (Sandbox Code Playgroud) 我想要实现什么?我想获取捕获图像的URI并将其保存在Firebase上.我尝试了什么?首先,我需要打开相机.以下是我的表现:
Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
if (cameraIntent.resolveActivity(getActivity().getPackageManager()) != null)
startActivityForResult(cameraIntent, CAMERA_REQUEST_CODE);
Run Code Online (Sandbox Code Playgroud)
捕获图像后,我需要获取图像的URI.以下是我的表现:
if (resultCode == Activity.RESULT_OK) {
if (requestCode == CAMERA_REQUEST_CODE) {
if (data != null) {
if (data.getData() != null) {
Uri capturedImageUri = data.getData();
} else {
Toast.makeText(getContext(), getString(R.string.coudldnt_get_photo), Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(getContext(), getString(R.string.coudldnt_get_photo), Toast.LENGTH_SHORT).show();
}
Run Code Online (Sandbox Code Playgroud)
一切都很好.但仅限于某些设备.我认为它仅适用于超过21个设备的API级别.在其他设备中,getData()返回null.
那么,接下来我做了什么?我发现我可以通过以下代码获取图像的Bitmap:
Bitmap bitmap = (Bitmap)data.getExtras().get("data") ;
Run Code Online (Sandbox Code Playgroud)
所以,我有一个图像的位图.我需要获取此图像的URI.以下是我的表现:
public Uri getImageUri(Context inContext, Bitmap inImage) {
String path =
Images.Media.insertImage(inContext.getContentResolver(), inImage,
"Title", null);
return Uri.parse(path);
}
Run Code Online (Sandbox Code Playgroud)
上面的代码返回我的URI,但图像质量非常差.
所以,我一直在寻找解决方案.并且发现正确的方法是在我启动时创建文件 …
我已经在我的Android应用程序中集成了Snapchat的Creative Kit。处理之后,我从服务器收到了字节数组形式的图像,将其保存到磁盘,然后将文件发送到Snapchat的Creative Kit,如下所示。
private fun downloadImage(
fileName: String,
imageByteArray: ByteArray?): Uri? {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state) {
val downloadDir = File(
Environment.getExternalStorageDirectory(), context?.getString(R.string.app_name)
)
if (!downloadDir.isDirectory) {
downloadDir.mkdirs()
}
val file = File(downloadDir, fileName)
var ostream: FileOutputStream? = null
try {
ostream = FileOutputStream(file)
ostream.write(imageByteArray)
ostream.flush()
ostream.close()
}
} catch (e: IOException) {
e.printStackTrace()
}
val snapCreativeKitApi = SnapCreative.getApi(context!!)
val snapMediaFactory = SnapCreative.getMediaFactory(context!!)
lateinit var snapPhotoFile: SnapPhotoFile
try {
snapPhotoFile = snapMediaFactory.getSnapPhotoFromFile(file)
} catch (e: SnapMediaSizeException) …Run Code Online (Sandbox Code Playgroud)