安卓App调用相机拍照上传Firebase时崩溃问题求助
Hey there! Let's figure out why your app keeps crashing when trying to snap a photo and upload it to Firebase Storage. Since your code snippet cuts off halfway, I’ll walk through the most common culprits and fixes that usually resolve this kind of issue.
1. Missing or Misconfigured Permissions
Android 6.0+ requires dynamic permissions for camera access, and Android 13+ adds separate permissions for media access. Skipping this step is one of the top reasons for crashes here.
- First, add the required permissions to your
AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- For Android 13+ --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
- Then, request permissions dynamically before launching the camera:
private static final int PERMISSION_REQUEST_CODE = 100; private void checkAndRequestPermissions() { String[] requiredPermissions; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requiredPermissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_MEDIA_IMAGES}; } else { requiredPermissions = new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE}; } if (!hasAllPermissions(requiredPermissions)) { ActivityResultContracts.RequestMultiplePermissions contract = new ActivityResultContracts.RequestMultiplePermissions(); registerForActivityResult(contract, result -> { boolean allGranted = true; for (Boolean isGranted : result.values()) { if (!isGranted) { allGranted = false; break; } } if (allGranted) { launchCamera(); } else { Toast.makeText(this, "Camera and storage permissions are required", Toast.LENGTH_SHORT).show(); } }).launch(requiredPermissions); } else { launchCamera(); } } private boolean hasAllPermissions(String[] permissions) { for (String permission : permissions) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { return false; } } return true; }
2. Invalid Photo File/Uri Handling
Using a direct file path instead of FileProvider can cause security exceptions on newer Android versions, and missing file checks lead to FileNotFoundException crashes.
- Register
FileProviderin yourAndroidManifest.xml:
<application> <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" android:resource="@xml/file_paths" /> </provider> </application>
- Create
res/xml/file_paths.xmlto define allowed file paths:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="camera_photos" path="Pictures" /> </paths>
- Launch the camera with a secure file Uri:
private File photoFile; private ActivityResultLauncher<Intent> cameraLauncher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Initialize the camera launcher cameraLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK) { uploadToFirebase(); } else { Toast.makeText(this, "Photo capture cancelled", Toast.LENGTH_SHORT).show(); } }); } private void launchCamera() { Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); if (takePictureIntent.resolveActivity(getPackageManager()) == null) { Toast.makeText(this, "No camera app available", Toast.LENGTH_SHORT).show(); return; } try { photoFile = createTempPhotoFile(); } catch (IOException e) { Toast.makeText(this, "Failed to create photo file: " + e.getMessage(), Toast.LENGTH_SHORT).show(); return; } Uri photoUri = FileProvider.getUriForFile( this, getPackageName() + ".fileprovider", photoFile ); takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri); cameraLauncher.launch(takePictureIntent); } private File createTempPhotoFile() throws IOException { String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault()).format(new Date()); String fileName = "JPEG_" + timeStamp + "_"; File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES); return File.createTempFile(fileName, ".jpg", storageDir); }
3. Incomplete Firebase Upload Logic
Your code cuts off at the upload part, so here's a complete, crash-safe implementation:
private void uploadToFirebase() { if (photoFile == null || !photoFile.exists()) { Toast.makeText(this, "Photo file not found", Toast.LENGTH_SHORT).show(); return; } StorageReference storageRef = FirebaseStorage.getInstance().getReference(); StorageReference photoRef = storageRef.child("user_photos/" + photoFile.getName()); UploadTask uploadTask = photoRef.putFile(Uri.fromFile(photoFile)); uploadTask.addOnSuccessListener(taskSnapshot -> { Toast.makeText(this, "Upload successful!", Toast.LENGTH_SHORT).show(); // Optional: Get the download URL photoRef.getDownloadUrl().addOnSuccessListener(uri -> { String downloadUrl = uri.toString(); // Use this URL to store in Firestore or display the image }); }).addOnFailureListener(e -> { Toast.makeText(this, "Upload failed: " + e.getMessage(), Toast.LENGTH_SHORT).show(); }); }
4. Uncaught Exceptions
Always wrap file operations (like creating the temp photo file) in try-catch blocks, and check for null values before accessing objects. Also, check your Logcat for the exact crash stack trace—this will tell you if it's a NullPointerException, SecurityException, or something else.
If you can share the full crash log and your complete code, I can help narrow down the issue even more!
内容的提问来源于stack exchange,提问作者bancqm

