为什么“拍摄照片”按钮不起作用?
Why is the " TAKE A PHOTO" button not working?
我试着做了一些申请,所以我从 GitHub 那里借了一个。当我单击“拍摄照片”按钮时,它说应用程序没有响应。我认为问题与请求相机许可有关。
我将 targetSdkVersion 从 22 升级到 28,现在它不工作了。谁能帮帮我
这是selectimageactivity.java:
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.microsoft.projectoxford.face.samples.R;
import java.io.File;
import java.io.IOException;
// The activity for the user to select a image and to detect faces in the image.
public class SelectImageActivity extends AppCompatActivity {
// Flag to indicate the request of the next task to be performed
private static final int REQUEST_TAKE_PHOTO = 0;
private static final int REQUEST_SELECT_IMAGE_IN_ALBUM = 1;
// The URI of photo taken with camera
private Uri mUriPhotoTaken;
// When the activity is created, set all the member variables to initial state.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_image);
}
// Save the activity state when it's going to stop.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("ImageUri", mUriPhotoTaken);
}
// Recover the saved state when the activity is recreated.
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mUriPhotoTaken = savedInstanceState.getParcelable("ImageUri");
}
// Deal with the result of selection of the photos and faces.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode)
{
case REQUEST_TAKE_PHOTO:
case REQUEST_SELECT_IMAGE_IN_ALBUM:
if (resultCode == RESULT_OK) {
Uri imageUri;
if (data == null || data.getData() == null) {
imageUri = mUriPhotoTaken;
} else {
imageUri = data.getData();
}
Intent intent = new Intent();
intent.setData(imageUri);
setResult(RESULT_OK, intent);
finish();
}
break;
default:
break;
}
}
// When the button of "Take a Photo with Camera" is pressed.
public void takePhoto(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getPackageManager()) != null) {
// Save the photo taken to a temporary file.
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
try {
File file = File.createTempFile("IMG_", ".jpg", storageDir);
mUriPhotoTaken = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mUriPhotoTaken);
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
} catch (IOException e) {
setInfo(e.getMessage());
}
}
}
// When the button of "Select a Photo in Album" is pressed.
public void selectImageInAlbum(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_SELECT_IMAGE_IN_ALBUM);
}
}
// Set the information panel on screen.
private void setInfo(String info) {
TextView textView = (TextView) findViewById(R.id.info);
textView.setText(info);
}
}
然后是 build.gradle(模块):
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.microsoft.projectoxford.faceapisample"
minSdkVersion 22
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
// Include local lib mostly for debug purpose.
// implementation project(':lib')
// Use the following line to include client library for Face API from Maven Central Repository
implementation 'com.microsoft.projectoxford:face:1.4.4'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
implementation "com.android.support:design:28.0.0"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
这是我在 logcat 得到的错误。
enter image description here
从您的 logcat,您得到 FileUriExposedExceptiom 您需要创建 FileProvider 并使用它。
原因是针对 Android 7.0(API 级别 24)及更高版本的应用,跨包边界传递 file://URI 会导致 FileUriExposedException。
这里有更多信息以及如何拍照和使用 FileProvider
https://developer.android.com/training/camera/photobasics
https://developer.android.com/reference/androidx/core/content/FileProvider
首先,您必须在 AndroidManifest.xml 文件中的标记内声明此 FileProvider:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="androidx.core.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>
...
</application>
</manifest>
接下来,创建一个名为xml 的资源目录并创建一个fileprovider.xml。假设您希望授予对应用程序特定外部存储目录的访问权限,这不需要请求额外的权限,您可以按如下方式声明此行:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- See table below. The external-files-path DOES NOT require external storage permissions. -->
<external-files-path
name="images"
path="Pictures" />
<!--Uncomment below to share the entire application specific directory -->
<!--<external-path name="all_dirs" path="."/>-->
</paths>
最后,您将使用 FileProvider class:
将 File 对象转换为内容提供程序
// getExternalFilesDir() + "/Pictures" should match the declaration in fileprovider.xml paths
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = FileProvider.getUriForFile(MyActivity.this, "com.example.myapp.fileprovider", file);
我试着做了一些申请,所以我从 GitHub 那里借了一个。当我单击“拍摄照片”按钮时,它说应用程序没有响应。我认为问题与请求相机许可有关。 我将 targetSdkVersion 从 22 升级到 28,现在它不工作了。谁能帮帮我
这是selectimageactivity.java:
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.microsoft.projectoxford.face.samples.R;
import java.io.File;
import java.io.IOException;
// The activity for the user to select a image and to detect faces in the image.
public class SelectImageActivity extends AppCompatActivity {
// Flag to indicate the request of the next task to be performed
private static final int REQUEST_TAKE_PHOTO = 0;
private static final int REQUEST_SELECT_IMAGE_IN_ALBUM = 1;
// The URI of photo taken with camera
private Uri mUriPhotoTaken;
// When the activity is created, set all the member variables to initial state.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_image);
}
// Save the activity state when it's going to stop.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("ImageUri", mUriPhotoTaken);
}
// Recover the saved state when the activity is recreated.
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mUriPhotoTaken = savedInstanceState.getParcelable("ImageUri");
}
// Deal with the result of selection of the photos and faces.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode)
{
case REQUEST_TAKE_PHOTO:
case REQUEST_SELECT_IMAGE_IN_ALBUM:
if (resultCode == RESULT_OK) {
Uri imageUri;
if (data == null || data.getData() == null) {
imageUri = mUriPhotoTaken;
} else {
imageUri = data.getData();
}
Intent intent = new Intent();
intent.setData(imageUri);
setResult(RESULT_OK, intent);
finish();
}
break;
default:
break;
}
}
// When the button of "Take a Photo with Camera" is pressed.
public void takePhoto(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getPackageManager()) != null) {
// Save the photo taken to a temporary file.
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
try {
File file = File.createTempFile("IMG_", ".jpg", storageDir);
mUriPhotoTaken = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mUriPhotoTaken);
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
} catch (IOException e) {
setInfo(e.getMessage());
}
}
}
// When the button of "Select a Photo in Album" is pressed.
public void selectImageInAlbum(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_SELECT_IMAGE_IN_ALBUM);
}
}
// Set the information panel on screen.
private void setInfo(String info) {
TextView textView = (TextView) findViewById(R.id.info);
textView.setText(info);
}
}
然后是 build.gradle(模块):
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.microsoft.projectoxford.faceapisample"
minSdkVersion 22
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
// Include local lib mostly for debug purpose.
// implementation project(':lib')
// Use the following line to include client library for Face API from Maven Central Repository
implementation 'com.microsoft.projectoxford:face:1.4.4'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
implementation "com.android.support:design:28.0.0"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
这是我在 logcat 得到的错误。 enter image description here
从您的 logcat,您得到 FileUriExposedExceptiom 您需要创建 FileProvider 并使用它。
原因是针对 Android 7.0(API 级别 24)及更高版本的应用,跨包边界传递 file://URI 会导致 FileUriExposedException。
这里有更多信息以及如何拍照和使用 FileProvider
https://developer.android.com/training/camera/photobasics
https://developer.android.com/reference/androidx/core/content/FileProvider
首先,您必须在 AndroidManifest.xml 文件中的标记内声明此 FileProvider:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="androidx.core.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>
...
</application>
</manifest>
接下来,创建一个名为xml 的资源目录并创建一个fileprovider.xml。假设您希望授予对应用程序特定外部存储目录的访问权限,这不需要请求额外的权限,您可以按如下方式声明此行:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- See table below. The external-files-path DOES NOT require external storage permissions. -->
<external-files-path
name="images"
path="Pictures" />
<!--Uncomment below to share the entire application specific directory -->
<!--<external-path name="all_dirs" path="."/>-->
</paths>
最后,您将使用 FileProvider class:
将 File 对象转换为内容提供程序// getExternalFilesDir() + "/Pictures" should match the declaration in fileprovider.xml paths
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = FileProvider.getUriForFile(MyActivity.this, "com.example.myapp.fileprovider", file);