【问题标题】:Unable to get Write permission on Android无法在 Android 上获得写入权限
【发布时间】:2019-12-12 12:21:26
【问题描述】:

我正在开发一个应与 Google 日历交互的 Android 应用。我按照 Google API 网站上的说明,复制了这个类中的代码:

public class GoogleCalendarManager {
private static final String APPLICATION_NAME = "Locker";
private static final JacksonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";

/**
 * Global instance of the scopes required by this quickstart.
 * If modifying these scopes, delete your previously saved tokens/ folder.
 */
private static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR_READONLY);
private static final String CREDENTIALS_FILE_PATH = "/credentials.json";

private Calendar.Events events;
private Context context;

/**
 * Creates an authorized Credential object.
 * @param HTTP_TRANSPORT The network HTTP Transport.
 * @return An authorized Credential object.
 * @throws IOException If the credentials.json file cannot be found.
 */
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
    // Load client secrets.
    InputStream in = GoogleCalendarManager.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
    if (in == null) {
        Log.println(Log.DEBUG, "DEB", "------- FILE NOT FOUND ---------");
        throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
    } else {
        GoogleClientSecrets clientSecrets = GoogleClientSecrets
                .load(JSON_FACTORY, new InputStreamReader(in));

        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
                HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(
                        new File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();

        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8888).build();
        return new AuthorizationCodeInstalledApp(flow, receiver)
                .authorize("user");
    }
}

public GoogleCalendarManager(Context context) {
    this.context = context;
    // Build a new authorized API client service.
    NetHttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    try {
        HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
    } catch (GeneralSecurityException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Calendar service = null;
    try {
        service = new Calendar
                .Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
                .setApplicationName(APPLICATION_NAME)
                .build();

        this.events = service.events();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

public void addReminder(String domain, String username, String lastUpdate, int updatePeriodDays){
    Resources resources = context.getResources();

    Event event = new Event()
            .setSummary(resources.getString(R.string.event_summary) + domain)
            .setDescription(resources.getString(R.string.event_description)
                    + domain + ": " + username
                    + resources.getString(R.string.event_description_plus)
                    + lastUpdate);

    // Getting the date
    Date lastUpdateDate = null;
    try {
        lastUpdateDate = new SimpleDateFormat("dd/MM/yyyy")
                .parse(String.valueOf(lastUpdate));
    } catch (ParseException e) {
        e.printStackTrace();
    }

    long passPeriod = lastUpdateDate.getTime();
    long updatePeriod = TimeUnit.DAYS.toMillis(updatePeriodDays);
    long expirePeriod = passPeriod + updatePeriod;


    DateTime startDateTime = new DateTime(expirePeriod);
    EventDateTime start = new EventDateTime()
            .setDateTime(startDateTime);
    event.setStart(start);

    DateTime endDateTime = new DateTime(expirePeriod);
    EventDateTime end = new EventDateTime()
            .setDateTime(endDateTime);
    event.setEnd(end);

}
}

我的问题是 java.io.IOException: unable to create directory: /tokens 我尝试在其中创建文件夹,在这一行:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
            .setDataStoreFactory(new FileDataStoreFactory(
                    new File(TOKENS_DIRECTORY_PATH)))
            .setAccessType("offline")
            .build();

我已经尝试在我的应用的清单文件中添加权限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.locker">
    <uses-permission android:name="android.permission.INTERNET"></uses-permission>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
    <application
        ...
    </application>

</manifest>

我真的不知道如何在设备的内部存储上进行写入。我尝试在 File 构造函数中编写 String.valueOf(Environment.getDataDirectory())) 而不是常量 TOKENS_DIRECTORY_PATH ,但是我遇到了另一个错误,并且程序崩溃:

 java.lang.NoClassDefFoundError: Failed resolution of: Ljava/nio/file/attribute/PosixFilePermission;

我用模拟器和真实设备尝试了这两种情况,但错误没有改变。不知道怎么写权限。

谢谢!!!

更新 我在我的 Activity 中添加了这个方法,在创建 GoogleCalendarManager 之前执行:

public  boolean isStoragePermissionGranted() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                == PackageManager.PERMISSION_GRANTED) {
            Log.println(Log.DEBUG, "DEB","Permission is granted");
            return true;
        } else {
            Log.println(Log.DEBUG, "DEB","Permission is revoked");
            ActivityCompat.requestPermissions(this, new String[]{
                    Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
            return false;
        }
    }
    else { //permission is automatically granted on sdk<23 upon installation
        Log.println(Log.DEBUG, "DEB","Permission is granted");
        return true;
    }
}

它打印 Permission isgranted 但我遇到了和以前一样的错误。

【问题讨论】:

  • 我认为,您没有在运行时提供权限
  • 如何查看?
  • 您应该在运行时在 Android 6.0 及更高版本上提供所有权限。在您的应用的 MainActvity 中提供所有这些权限
  • 我添加了那个方法,但是同样的问题

标签: java android permissions


【解决方案1】:

您试图在没有适当调整的情况下在 Android 上为 java 运行稍有更改的示例。改编将包括许多步骤,而且看起来毫无用处,因为使用的库看起来在 Android 上并不完全支持。在移动设备上启动码头服务器实例看起来是多余的。

适应 Android 的第一步可能是:

1. 在这里致电context.getFilesDir() 而不是new File(TOKENS_DIRECTORY_PATH)

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
        HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
        .setDataStoreFactory(new FileDataStoreFactory(
                new File(TOKENS_DIRECTORY_PATH)))
        .setAccessType("offline")
        .build();

对于(您的应用程序的)内部存储,您不需要任何权限。

  1. 使用AssetManager API 代替GoogleCalendarManager.class.getResourceAsStream(CREDENTIALS_FILE_PATH) 等访问资源文件)

我建议使用标准的Calendar Provider for Android 或REST API

【讨论】:

  • 成功了,谢谢!现在我正在尝试连接 Google 日历帐户
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-26
相关资源
最近更新 更多