如何在我的 Android 应用程序上实现 Dropbox oAuth2 流程方法

问题描述 投票:0回答:1

我想在我的 Android 应用程序上实现 Dropbox oAuth2 流方法,以便用户可以获得刷新访问令牌,而无需每 4 小时更新我的代码我已经向我的相机应用程序添加了一个密钥,因此当用户单击它时,它会打开 oAuth 流操作但是当我按下它时我遇到了问题,然后它在谷歌中打开我设计的网址,然后我在保管箱的网站中按允许,我在我的网址中获得了授权代码,然后我直接返回到应用程序,但是当我按照片拍摄徽标拍照应用程序不断崩溃 这是我的应用程序代码

这是我的应用程序代码 `公共类 MainActivity 扩展 AppCompatActivity 实现 View.OnClickListener {

private static final int CAMERA_PERMISSION_REQUEST = 100;
private static final String[] REQUIRED_CAMERA_PERMISSIONS = new String[]{Manifest.permission.CAMERA};

private static final String DROPBOX_APP_KEY = "hc2p6uj44p9pyoc";
private static final String DROPBOX_APP_SECRET = "this is my secret code i cannot showed it";
private static final String DROPBOX_REDIRECT_URI = "https://decamera://auth-finish";

private String DROPBOX_ACCESS_TOKEN = null;
private PreviewView previewView;
private ImageCapture imageCapture;
private TextView addressTextView;

private ExecutorService cameraExecutor = Executors.newSingleThreadExecutor();
private FusedLocationProviderClient fusedLocationProviderClient;
private Geocoder geocoder;

// Add latitude and longitude variables
private double latitudeValue;
private double longitudeValue;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    previewView = findViewById(R.id.previewView);
    ImageButton captureButton = findViewById(R.id.captureButton);
    ImageButton leftCornerButton = findViewById(R.id.leftCornerButton);
    addressTextView = findViewById(R.id.addressTextView);

    fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(this);
    geocoder = new Geocoder(this, Locale.getDefault());

    captureButton.setOnClickListener(this);

    leftCornerButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            initiateDropboxAuthorization();
        }
    });

    addressTextView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showEditAddressDialog();
        }
    });

    if (allPermissionsGranted()) {
        startCamera();
        getLastLocation();
    } else {
        ActivityCompat.requestPermissions(this, REQUIRED_CAMERA_PERMISSIONS, CAMERA_PERMISSION_REQUEST);
    }

    // Initialize Dropbox access token if available
    SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
    DROPBOX_ACCESS_TOKEN = prefs.getString("dropboxAccessToken", null);

    // Check if the app was opened with a Dropbox authorization callback
    handleDropboxAuthorizationCallback(getIntent());
}

// Override onNewIntent to handle the Dropbox authorization callback
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    handleDropboxAuthorizationCallback(intent);
}
private void initiateDropboxAuthorization() {
    // Construct the Dropbox authorization URL
    String authorizationUrl = "https://www.dropbox.com/oauth2/authorize" +
            "?client_id=" + DROPBOX_APP_KEY +
            "&response_type=code" +
            "&token_access_type=offline" +
            "&state=myState" +  // Replace with your own state
            "&redirect_uri=" + DROPBOX_REDIRECT_URI;

    // Open the authorization URL in a web browser or WebView
    Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(authorizationUrl));
    startActivity(browserIntent);
}
private String performPostRequest(String requestUrl, String urlParameters) {
    try {
        URL url = new URL(requestUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        connection.setRequestProperty("Content-Length", Integer.toString(urlParameters.getBytes().length));
        connection.setDoOutput(true);

        // Log the request details
        Log.d("Dropbox", "POST Request URL: " + requestUrl);
        Log.d("Dropbox", "POST Request Body: " + urlParameters);

        // Write the request body
        try (DataOutputStream wr = new DataOutputStream(connection.getOutputStream())) {
            wr.writeBytes(urlParameters);
            wr.flush();
        }

        // Get the response
        try (InputStream is = connection.getInputStream();
             BufferedReader rd = new BufferedReader(new InputStreamReader(is))) {
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = rd.readLine()) != null) {
                response.append(line);
                response.append('\r');
            }

            // Log the response
            Log.d("Dropbox", "POST Response: " + response.toString());

            return response.toString();
        }
    } catch (Exception e) {
        // Log any exceptions
        Log.e("Dropbox", "Error in HTTP request: " + e.getMessage());
        return null;
    }
}
private void handleDropboxAuthorizationCallback(Intent intent) {
    Uri data = intent.getData();
    if (data != null && data.toString().startsWith(DROPBOX_REDIRECT_URI)) {
        // Authorization successful, extract the authorization code
        String code = data.getQueryParameter("code");

        // Log the authorization code for debugging
        Log.d("Dropbox", "Authorization Code: " + code);

        // Now, exchange the authorization code for an access token and refresh token
        exchangeAuthorizationCodeForTokens(code);
    }
}
private void exchangeAuthorizationCodeForTokens(String code) {
    try {
        String url = "https://api.dropbox.com/oauth2/token";
        String requestBody = "code=" + code +
                "&grant_type=authorization_code" +
                "&client_id=" + DROPBOX_APP_KEY +
                "&client_secret=" + DROPBOX_APP_SECRET +
                "&redirect_uri=" + DROPBOX_REDIRECT_URI;

        // Log the request details
        Log.d("Dropbox", "Token Exchange Request URL: " + url);
        Log.d("Dropbox", "Token Exchange Request Body: " + requestBody);

        // Perform the POST request and obtain the JSON response
        String jsonResponse = performPostRequest(url, requestBody);

        // Log the response
        Log.d("Dropbox", "Token Exchange Response: " + jsonResponse);

        // Parse the JSON response to extract access and refresh tokens
        JSONObject jsonObject = new JSONObject(jsonResponse);
        DROPBOX_ACCESS_TOKEN = jsonObject.getString("access_token");

        // Log the obtained access token
        Log.d("Dropbox", "Access Token Obtained: " + DROPBOX_ACCESS_TOKEN);

        // Save the Dropbox access token
        SharedPreferences prefs = getPreferences(Context.MODE_PRIVATE);
        prefs.edit().putString("dropboxAccessToken", DROPBOX_ACCESS_TOKEN).apply();

    } catch (Exception e) {
        // Log any exceptions
        Log.e("Dropbox", "Error in token exchange: " + e.getMessage());
    }
}



private void showEditAddressDialog() {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Edit Address");

    // Set up the input
    View viewInflated = LayoutInflater.from(this).inflate(R.layout.edit_address_dialog, null);
    final EditText input = viewInflated.findViewById(R.id.editTextAddress);
    input.setText(addressTextView.getText()); // Pre-fill with existing address
    builder.setView(viewInflated);

    // Set up buttons
    builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // Update the addressTextView with the edited address
            String editedAddress = input.getText().toString();
            addressTextView.setText(editedAddress);
        }
    });

    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.cancel(); // Cancel the update
        }
    });

    // Make the dialog cancelable by tapping outside
    builder.setCancelable(true);

    // Show the dialog
    builder.show();
}

private boolean allPermissionsGranted() {
    for (String permission : REQUIRED_CAMERA_PERMISSIONS) {
        if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
            return false;
        }
    }
    return true;
}

private void startCamera() {
    ListenableFuture<ProcessCameraProvider> cameraProviderFuture = ProcessCameraProvider.getInstance(this);

    cameraProviderFuture.addListener(() -> {
        try {
            ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
            bindPreview(cameraProvider);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }, ContextCompat.getMainExecutor(this));
}

private void bindPreview(ProcessCameraProvider cameraProvider) {
    Preview preview = new Preview.Builder().build();

    CameraSelector cameraSelector = new CameraSelector.Builder()
            .requireLensFacing(CameraSelector.LENS_FACING_BACK)
            .build();

    Camera camera = cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview);

    preview.setSurfaceProvider(previewView.getSurfaceProvider());

    imageCapture = new ImageCapture.Builder()
            .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
            .setTargetRotation(previewView.getDisplay().getRotation())
            .build();

    cameraProvider.unbindAll();
    cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview, imageCapture);
}
private void combineImageWithAddressAndChoices(File photoFile, String addressText, String firstQuestionChoice, String secondQuestionChoice, double latitude, double longitude) {
    Bitmap photoBitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());

    int rotation = getRotationAngle(photoFile.getAbsolutePath());
    if (rotation != 0) {
        photoBitmap = rotateBitmap(photoBitmap, rotation);
    }

    Bitmap combinedBitmap = photoBitmap.copy(photoBitmap.getConfig(), true);
    Canvas canvas = new Canvas(combinedBitmap);

    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setTypeface(Typeface.create(Typeface.DEFAULT, Typeface.BOLD));

    float x = 130;
    float yAddress = combinedBitmap.getHeight() - 800 + 130;
    float yTimestamp = yAddress + paint.getTextSize() + 130; // Add more space between lines
    float yFirstChoice = yTimestamp + paint.getTextSize() + 130; // Add more space between lines
    float ySecondChoice = yFirstChoice + paint.getTextSize() + 130; // Add more space between lines
    float yCoordinates = ySecondChoice + paint.getTextSize() + 130; // Add more space between lines

    // Increase text size
    float textSize = 130; // Adjust the text size as needed
    paint.setTextSize(textSize);

    // Add address with background
    drawTextWithBackground(canvas, paint, "Address: " + addressText, x, yAddress);

    // Add timestamp with background
    String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).format(new Date());
    drawTextWithBackground(canvas, paint, "Timestamp: " + timeStamp, x, yTimestamp);

    // Add user's choices with background
    drawTextWithBackground(canvas, paint, "Betons: " + firstQuestionChoice, x, yFirstChoice);
    drawTextWithBackground(canvas, paint, "Holzes: " + secondQuestionChoice, x, ySecondChoice);

    // Add coordinates with background
    String coordinatesText = String.format(Locale.getDefault(), "Latitude: %.6f, Longitude: %.6f", latitude, longitude);
    drawTextWithBackground(canvas, paint, coordinatesText, x, yCoordinates);

    saveCombinedImage(combinedBitmap, photoFile);
}

// Helper method to draw text with background
private void drawTextWithBackground(Canvas canvas, Paint paint, String text, float x, float y) {
    // Get text bounds to determine the background width and height
    Rect bounds = new Rect();
    paint.getTextBounds(text, 0, text.length(), bounds);

    // Add a semi-transparent background for the text
    paint.setColor(Color.parseColor("#80000000")); // Adjust the color and transparency as needed
    RectF backgroundRect = new RectF(x, y - bounds.height() + 20, x + bounds.width() + 40, y + 20);
    canvas.drawRect(backgroundRect, paint);
    paint.setColor(Color.WHITE); // Set text color back to white

    // Draw the text
    canvas.drawText(text, x + 20, y, paint);
}

private void getLastLocation() {
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        fusedLocationProviderClient.getLastLocation()
                .addOnSuccessListener(this, new OnSuccessListener<Location>() {
                    @Override
                    public void onSuccess(Location location) {
                        if (location != null) {
                            latitudeValue = location.getLatitude();
                            longitudeValue = location.getLongitude();
                            updateAddress(location);
                        }
                    }
                });
    } else {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, CAMERA_PERMISSION_REQUEST);
    }
}

private void updateAddress(Location location) {
    try {
        List<Address> addresses = geocoder.getFromLocation(location.getLatitude(), location.getLongitude(), 1);
        if (addresses != null && addresses.size() > 0) {
            Address address = addresses.get(0);
            String fullAddress = address.getAddressLine(0);
            addressTextView.setText(fullAddress);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

private void captureImage() {
    // Create an AlertDialog to ask the user the first question
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Was ist die Art des Betons?");

    // Add options to the dialog
    String[] options = {"steif", "plastisch", "fließfähig"};
    builder.setItems(options, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // Handle the user's choice
            String firstQuestionChoice = options[which];

            // Now, ask the user the second question
            askSecondQuestion(firstQuestionChoice);
        }
    });

    // Show the dialog
    builder.show();
}

private void askSecondQuestion(String firstQuestionChoice) {
    // Create an AlertDialog to ask the user the second question
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("Was ist die Art des holz?");

    // Add options to the dialog
    String[] options = {"Fichtenholz", "Eichenholz", "Buchenholz"};
    builder.setItems(options, new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // Handle the user's choice for the second question
            String secondQuestionChoice = options[which];

            // Now, capture the image with both choices
            captureImageAfterUserChoices(firstQuestionChoice, secondQuestionChoice);
        }
    });

    // Show the dialog
    builder.show();
}

private void captureImageAfterUserChoices(String firstQuestionChoice, String secondQuestionChoice) {
    // Now, capture the image as before

    File photoFile = createImageFile();
    if (photoFile != null) {
        ImageCapture.OutputFileOptions outputFileOptions =
                new ImageCapture.OutputFileOptions.Builder(photoFile).build();

        imageCapture.takePicture(outputFileOptions, ContextCompat.getMainExecutor(this), new ImageCapture.OnImageSavedCallback() {
            @Override
            public void onImageSaved(@Nullable ImageCapture.OutputFileResults outputFileResults) {
                // Combine the image with the edited address, timestamp, latitude, and longitude before uploading to Dropbox
                combineImageWithAddressAndChoices(photoFile, addressTextView.getText().toString(), firstQuestionChoice, secondQuestionChoice, latitudeValue, longitudeValue);

                // Show the drawn photo to the user before uploading
                showPreviewDialog(photoFile);
            }

            @Override
            public void onError(@NonNull ImageCaptureException exception) {
                runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error capturing image: " + exception.getMessage(), Toast.LENGTH_SHORT).show());
            }
        });

    } else {
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error creating photo file", Toast.LENGTH_SHORT).show());
    }
}

// Helper method to show a preview dialog to the user
private void showPreviewDialog(File photoFile) {
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle("To DropBox Server");

    // Inflate the layout containing an ImageView
    View viewInflated = LayoutInflater.from(this).inflate(R.layout.preview_dialog, null);
    ImageView imageViewPreview = viewInflated.findViewById(R.id.imageViewPreview);
    imageViewPreview.setImageBitmap(BitmapFactory.decodeFile(photoFile.getAbsolutePath()));

    builder.setView(viewInflated);

    // Set up buttons
    builder.setPositiveButton("Confirm", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // Call the AsyncTask to upload the combined photo to Dropbox in the background
            new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... voids) {
                    uploadToDropbox(photoFile);
                    return null;
                }
            }.execute();
        }
    });

    builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // Delete the temporary photo file
            if (photoFile.exists()) {
                photoFile.delete();
            }
        }
    });

    // Make the dialog cancelable by tapping outside
    builder.setCancelable(true);

    // Show the dialog
    builder.show();
}

private File createImageFile() {
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US).format(new Date());
    String imageFileName = "JPEG_" + timeStamp + "_";
    File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);

    try {
        if (storageDir != null) {
            File tempFile = File.createTempFile(imageFileName, ".jpg", storageDir);
            System.out.println("File path: " + tempFile.getAbsolutePath());
            return tempFile;
        } else {
            runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error creating storage directory", Toast.LENGTH_SHORT).show());
        }
    } catch (IOException e) {
        e.printStackTrace();
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error creating photo file: " + e.getMessage(), Toast.LENGTH_SHORT).show());
    }

    return null;
}

private int getRotationAngle(String imagePath) {
    ExifInterface exifInterface;
    try {
        exifInterface = new ExifInterface(imagePath);
    } catch (IOException e) {
        e.printStackTrace();
        return 0;
    }

    int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);

    switch (orientation) {
        case ExifInterface.ORIENTATION_ROTATE_90:
            return 90;
        case ExifInterface.ORIENTATION_ROTATE_180:
            return 180;
        case ExifInterface.ORIENTATION_ROTATE_270:
            return 270;
        default:
            return 0;
    }
}

private Bitmap rotateBitmap(Bitmap bitmap, int angle) {
    Matrix matrix = new Matrix();
    matrix.postRotate(angle);
    return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}

private void saveCombinedImage(Bitmap combinedBitmap, File photoFile) {
    try {
        FileOutputStream out = new FileOutputStream(photoFile);
        combinedBitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
        out.flush();
        out.close();
    } catch (IOException e) {
        e.printStackTrace();
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error combining image with address: " + e.getMessage(), Toast.LENGTH_SHORT).show());
    }
}

private void uploadToDropbox(File photoFile) {
    if (photoFile == null || !photoFile.exists()) {
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error: Photo file does not exist", Toast.LENGTH_SHORT).show());
        return;
    }

    if (DROPBOX_ACCESS_TOKEN == null) {
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error: Dropbox access token is null", Toast.LENGTH_SHORT).show());
        return;
    }

    DbxRequestConfig config = DbxRequestConfig.newBuilder("Decamera").build();
    DbxClientV2 client = new DbxClientV2(config, DROPBOX_ACCESS_TOKEN);

    try {
        String remotePath = "/Decamera/" + photoFile.getName();

        try (InputStream in = new FileInputStream(photoFile)) {
            client.files().uploadBuilder(remotePath)
                    .withMode(WriteMode.ADD)
                    .uploadAndFinish(in);

            runOnUiThread(() -> Toast.makeText(MainActivity.this, "Photo uploaded to Dropbox", Toast.LENGTH_SHORT).show());
        }

    } catch (Exception e) {
        e.printStackTrace();
        runOnUiThread(() -> Toast.makeText(MainActivity.this, "Error uploading to Dropbox: " + e.getMessage(), Toast.LENGTH_SHORT).show());
    }
}

@Override
public void onClick(View v) {
    if (v.getId() == R.id.captureButton) {
        captureImage();
    }
}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    if (requestCode == CAMERA_PERMISSION_REQUEST) {
        if (allPermissionsGranted()) {
            startCamera();
            getLastLocation();
        } else {
            runOnUiThread(() -> Toast.makeText(this, "Camera permissions not granted.", Toast.LENGTH_SHORT).show());
            finish();
        }
    }
}

}`

java android oauth-2.0 dropbox
1个回答
0
投票

这是我的日志猫 致命异常:主要 进程:com.example.decamera,PID:10620 java.lang.NullPointerException:尝试调用虚拟方法 'void androidx.camera.core.ImageCapture.takePicture(androidx.camera.core.ImageCapture$OutputFileOptions, java.util.concurrent.Executor, androidx.camera.core.ImageCapture$OnImageSavedCallback )' 在空对象引用上 在com.example.decamera.MainActivity.captureImageAfterUserChoices(MainActivity.java:472) 在 com.example.decamera.MainActivity.access$700(MainActivity.java:77) 在 com.example.decamera.MainActivity$7.onClick(MainActivity.java:456) 在 androidx.appcompat.app.AlertController$AlertParams$3.onItemClick(AlertController.java:1068) 在 android.widget.AdapterView.performItemClick(AdapterView.java:362) 在 android.widget.AbsListView.performItemClick(AbsListView.java:1689) 在 android.widget.AbsListView$PerformClick.run(AbsListView.java:4130) 在 android.widget.AbsListView$7.run(AbsListView.java:6612) 在 android.os.Handler.handleCallback(Handler.java:873) 在 android.os.Handler.dispatchMessage(Handler.java:99) 在 android.os.Looper.loop(Looper.java:214) 在 android.app.ActivityThread.main(ActivityThread.java:7078) 在 java.lang.reflect.Method.invoke(本机方法) 在 com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:964)

© www.soinside.com 2019 - 2024. All rights reserved.