Разрешения пользователя во время выполнения на Android API 26+ - PullRequest
0 голосов
/ 11 декабря 2018

После изменения моего целевого Android API на 26 мое приложение падает при записи с использованием внешнего FileHandle.У меня это работало при нацеливании на более низкий API (20), добавив их в мой AndroidManifest.xml:

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

Но через несколько месяцев Google изменил минимальный API на 26, что требует обработки прав пользователя во время выполнения, поэтомуЗаписи AndroidManifest больше не достаточно, чтобы заставить ее работать.

У меня нет опыта работы с кодом, специфичным для Android, потому что все, что мне нужно было сделать до этого момента, я смог сделать полностью в LibGDX.Вот учебник, который я нашел для разрешения на внешнее чтение в Android, но я не уверен, как заставить это работать в проекте LigGDX (я не смог найти никаких руководств по LibGDX по этому вопросу).Это то, что мне нужно сделать, и это будет идти в AndroidLauncher.java или ему нужен отдельный файл в проекте Android?

Код: https://codinginflow.com/tutorials/android/run-time-permission-request

Ассоциированное видеоУчебное пособие: https://www.youtube.com/watch?v=SMrB97JuIoM

Вот мой простой пример LibGDX, который работает, если я нацеливаюсь на более низкий API (20), но происходит сбой, когда я изменяю его на API 26, потому что я не обрабатываю права пользователя во время выполнения.В моем примере нажатие кнопки «PRESS» приводит к сохранению строки в текстовом документе через JSON.Затем строка считывается обратно из текстового файла в метку и отображается на экране.Счетчик увеличивается при каждом нажатии кнопки, чтобы показать, что произошло новое событие сохранения и загрузки.

Если кто-то может помочь заставить мою программу-пример работать с API 26 (или более поздней версии) или предоставить другой рабочий пример вLibGDX, который я мог бы загрузить, запустить и проверить, я был бы очень признателен.Спасибо.

Test.java

public class Test implements ApplicationListener {
    private Stage stage;
    private Window window;
    private Graphics graphics;

    @Override
    public void create () {
        stage = new Stage();
        stage.setViewport(new ScreenViewport(stage.getViewport().getCamera()));
        Gdx.input.setInputProcessor(stage);

        graphics = new Graphics();
        window = new Window(graphics);
        stage.addActor(window);
    }

    @Override
    public void render () {
        Gdx.gl.glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        stage.act(Gdx.graphics.getRawDeltaTime());
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        stage.getViewport().update(width, height, true);
    }

    @Override
    public void pause() { }
    @Override
    public void resume() { }

    @Override
    public void dispose () {
        stage.dispose();
        graphics.dispose();
    }
}

Window.java

public class Window extends Table {
    Graphics graphics;
    FileHandle handle;
    Label label;
    int count=0;

    public Window(Graphics graphics){
        setFillParent(true);
        this.graphics = graphics;
        handle = Gdx.files.getFileHandle("ZTEST/test.txt", getFileType());

        // label
        Label.LabelStyle labelStyle = new Label.LabelStyle();
        labelStyle.font = graphics.getFont();
        labelStyle.fontColor = Color.WHITE;
        label = new Label("", labelStyle);
        label.setAlignment(Align.center);
        add(label).size(graphics.programWidth*0.4f,graphics.programWidth*0.14f);
        label.debug();
        row().pad(graphics.programWidth*0.1f);

        // button
        TextButton.TextButtonStyle buttonStyle = new TextButton.TextButtonStyle();
        buttonStyle.font = graphics.getFont();
        buttonStyle.fontColor = Color.WHITE;
        final TextButton button = new TextButton("PRESS", buttonStyle);
        button.addListener(new ClickListener(){
            @Override
            public void clicked(InputEvent event, float x, float y){
                // SAVE TO DISK
                save(++count);

                // LOAD FROM DISK
                load();
            }
        });
        add(button).size(graphics.programWidth*0.4f,graphics.programWidth*0.14f);
        button.debug();
    }
    private Files.FileType getFileType(){
        switch(Gdx.app.getType()){
            case Desktop:
                return Files.FileType.Local;
            default:
                return Files.FileType.External;
        }
    }

    private void save(int count){
        Json json = new Json();
        json.setOutputType(JsonWriter.OutputType.json);
        handle.writeString(json.prettyPrint("save: "+count), false);
    }
    private void load(){
        if(handle.exists()){
            final Json json = new Json();
            label.setText(json.fromJson(null, handle.readString()).toString());
        }
    }
}

Graphics.java (Создает растровый шрифт)

public class Graphics implements Disposable {
    public final int programWidth;
    BitmapFont font;

    public Graphics(){
        programWidth = (Gdx.graphics.getWidth() < Gdx.graphics.getHeight()) ? Gdx.graphics.getWidth() : Gdx.graphics.getHeight();
        font = generateNumberFont();
    }
    private BitmapFont generateNumberFont(){
        final FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("internal/arialbd.ttf"));
        final FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
        parameter.characters = "abcdefthijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890:";
        parameter.size = (int)(programWidth*0.08f);
        final BitmapFont font = generator.generateFont(parameter);
        generator.dispose();
        return font;
    }

    public BitmapFont getFont(){ return font; }

    @Override
    public void dispose() {
        font.dispose();
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.tekker.test" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/GdxTheme" >
        <activity
            android:name="com.tekker.test.AndroidLauncher"
            android:label="@string/app_name" 
            android:screenOrientation="fullUser"
            android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>
...