Mengelola Perizinan (Permission) pada Aplikasi Android

Bagikan jika Anda sukai postingan ini!

Permintaan izin mengirim SMS
Permintaan izin mengirim SMS

Minggu-minggu ini ramai pemberitaan tentang VPN (Virtual Private Newtwork). Hampir setiap pengguna internet memperbincangkannya. Pasalnya karena pemerintah memblokir akses internet ke beberapa media sosial seperti Facebook, Instagram, Twitter, hingga Whatsapp. Otomatis para pengguna media sosial merasa terganggu dan mencari cara untuk dapat tetap mengakses media sosial yang mereka gunakan. Maklum saja, saat ini media sosial bukan hanya sarana untuk sekedar hubungan sosial atau sarana eksis saja. Lebih dari itu, sosial media sudah banyak digunakan sebagai jalan penghidupan dengan berjualan jasa maupun barang secara daring (online).

Salah satu cara untuk tetap dapat menggunakan sosial media adalah dengan menggunakan VPN (Virtual Private Newtwork). Untuk para pengguna Android dapat menggunakan aplikasi-aplikasi penyedia layanan VPN di PlayStore. Hingga kemudian muncul banyak isu tentang VPN, salah satunya adalah dapat mengambil informasi pribadi, hingga dapat menguras saldo tabungan. Semakin heboh karena pemerintah melalui Kementrian Komunikasi dan Informatika mengaminkan bahaya VPN dan mengimbau pengguna internet tidak menggunakan VPN.

Geli memang mendengarnya, apalagi bagi yang sudah terbiasa menggunakan VPN.

Sebagai pengembang aplikasi Android, saya menyangsikan isu tersebut. Karena sejauh ini, PlayStore cukup ketat menyaring aplikasi yang dipasarkan pada marketplace tersebut. Apalagi untuk aplikasi yang terhubung dengan internet. Banyak perizinan yang harus dilalui oleh aplikasi hingga dapat digunakan oleh pengguna. Baik perizinan dari sisi marketplace (PlayStore) maupun perizinan yang harus diberikan manual oleh pengguna. Ditambah lagi, beberapa pabrikan sudah menerapkan sistem perizinan sendiri untuk menjaga keamanan pengguna.

Jangankan untuk membaca data sensitif, untuk dapat membaca dan menulis pada media penyimpanan perangkat saja, aplikasi harus meminta dan mendapat perizinan dari pengguna.

Berikut ini saya akan mencoba membuat sebuah aplikasi demo untuk meminta perizinan pengguna. Mari kita mulai dengan membuat proyek baru. Pilih Basic Activity sebagai main activity kemudian sesuaikan pengaturannya seperti di bawah ini.

  • Name: Permission
  • Package: com.inochi.permission
  • Language: Java
Proyek Baru Permission
Proyek Baru Permission

Saya menambahkan beberapa kelas baru pada proyek, yaitu: Constants, Settings, dan BundleSettings. Kelas Constants digunakan untuk menyimpan daftar konstanta yang akan digunakan oleh proyek. Kelas Settings digunakan untuk komunikasi aplikasi dengan perangkat untuk keperluan penyimpanan pengaturan (settings). Kelas BundleSettings digunakan untuk membuat fungsi-fungsi berbagai penyimpanan pengaturan yang diperlukan.

Silakan menambahkan kelas-kelas terebut pada paket aplikasi Anda.

Constants

package com.inochi.permission;

public final class Constants {
    public static class Default {
        public static final String APPNAME = "com.inochi.permission";
        private static final int REQUEST = 1000;
    }

    public static final class Permission {
        public static final class Type {
            public static final int RECEIVE_BOOT_COMPLETED = Default.REQUEST + 1;
            public static final int READ_EXTERNAL_STORAGE = Default.REQUEST + 2;
            public static final int WRITE_EXTERNAL_STORAGE = Default.REQUEST + 3;
            public static final int SEND_SMS = Default.REQUEST + 4;
        }
    }

    public static final class Settings {
        public static final class Key {
            public static final String BOOT_PERMISSION = Default.APPNAME + "BOOT_PERMISSION";
        }
    }
}

Settings

package com.inochi.permission;

import android.content.Context;
import android.content.SharedPreferences;

public class Settings {
    private SharedPreferences settings;
    private Context context;
    private String name;

    public Settings(Context context, String name){
        this.context = context;
        this.name = name;
        settings = context.getSharedPreferences(name, Context.MODE_PRIVATE);
    }

    public Settings(Context context){
        this(context, context.getPackageName());
    }

    public void setSetting(String key, String value){
        SharedPreferences.Editor editor = settings.edit();
        editor.putString(key, value);
        editor.apply();
    }

    public void deleteSetting(){
        settings = context.getSharedPreferences(name, Context.MODE_PRIVATE);
        settings.edit().clear().apply();
    }

    public String getSetting(String key, String defVal){
        return settings.getString(key, defVal);
    }

    public String getSetting(String key){
        return settings.getString(key, "");
    }

    public int getIntSetting(String strKey, int defVal){
        String strValue = String.valueOf(defVal);
        String strSetting = getSetting(strKey, strValue);

        return Integer.parseInt(strSetting);
    }

    public int getIntSetting(String strKey){
        String strSetting = getSetting(strKey);
        return Integer.parseInt(strSetting);
    }

    public void setIntSetting(String strKey, int defVal){
        String strValue = String.valueOf(defVal);
        setSetting(strKey, strValue);
    }

    public short getShortSetting(String strKey, short defVal){
        String strValue = String.valueOf(defVal);
        String strSetting = getSetting(strKey, strValue);
        return Short.parseShort(strSetting);
    }

    public void setShortSetting(String strKey, short defVal){
        String strValue = String.valueOf(defVal);
        setSetting(strKey, strValue);
    }

    public long getLongSetting(String strKey, long defVal){
        String strValue = String.valueOf(defVal);
        String strSetting = getSetting(strKey, strValue);

        return Long.parseLong(strSetting);
    }

    public long getLongSetting(String strKey){
        String strSetting = getSetting(strKey);
        return Long.parseLong(strSetting);
    }

    public void setLongSetting(String strKey, long defVal){
        String strValue = String.valueOf(defVal);
        setSetting(strKey, strValue);
    }
}

BundleSettings

package com.inochi.permission;

import android.content.Context;

public class BundleSettings {
    private Context context;
    private Settings settings;

    public BundleSettings(Context context){
        this.context = context;
        this.settings = new Settings(context);
    }

    public int getBootPremission(){
        return settings.getIntSetting(Constants.Settings.Key.BOOT_PERMISSION, 0);
    }

    public void setBootPremission(int value){
        settings.setIntSetting(Constants.Settings.Key.BOOT_PERMISSION, value);
    }
}

Selanjutnya kita harus menambahkan jenis-jenis perizinan ini pada manifest. Klik ganda cabang manifests di bawah cabang app pada panel Project.

Tambahkan skrip berikut ini di dalam tag manifest sebelum tag application.

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

Sehingga lengkapnya akan menjadi seperti di bawah ini.

<?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.inochi.permission">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.SEND_SMS" />
    
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Selanjutnya, buka kelas MainActivity dan ubah kode seumbernya menjadi seperti di bawah ini.

package com.inochi.permission;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;

public class MainActivity extends AppCompatActivity {
    private BundleSettings bundleSettings;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        bundleSettings = new BundleSettings(this);

        setPermission();
    }

    @SuppressLint("InlinedApi")
    private void setPermission(){
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.RECEIVE_BOOT_COMPLETED)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.RECEIVE_BOOT_COMPLETED},
                    Constants.Permission.Type.RECEIVE_BOOT_COMPLETED);
        } else if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                    Constants.Permission.Type.READ_EXTERNAL_STORAGE);
        } else if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    Constants.Permission.Type.WRITE_EXTERNAL_STORAGE);
        } else if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS)
                != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.SEND_SMS},
                    Constants.Permission.Type.SEND_SMS);
        } else {
            int bootPermission = bundleSettings.getBootPremission();
            
            if (bootPermission == 0){
                runAutoStartCustom();
            }
        }
    }

    private static final Intent[] AUTO_START_INTENTS = {
            new Intent().setComponent(new ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")),
            new Intent("miui.intent.action.OP_AUTO_START").addCategory(Intent.CATEGORY_DEFAULT),
            new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")),
            new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
            new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")),
            new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
            new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
            new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
            new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
            new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
            new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
            new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")).setData(
                    Uri.parse("mobilemanager://function/entry/AutoStart"))
    };

    private void runAutoStartCustom(){
        try {
            for (Intent intent : AUTO_START_INTENTS){
                if (getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
                    startActivity(intent);
                    bundleSettings.setBootPremission(1);
                    break;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        try {
            setPermission();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Sekarang coba jalankan aplikasi Anda. Saat pertama kali dijalankan aplikasi akan menampilkan kotak pesan meminta perizinan dari aplikasi. Bacalah dengan seksama permintaan perizinan. Tolak jika Anda keberatan. Contohnya saat aplikasi meminta perizinan untuk mengirim SMS atau menelpon atau mengubah sistem. Namun, jika Anda menolak, dipastikan maka aplikasi tidak akan berjalan secara normal.

Permintaan izin untuk menulis dan membaca pada media penyimpanan
Permintaan izin untuk menulis dan membaca pada media penyimpanan

Setelah proses permintaan izin, pada beberapa perangkat akan memunculkan activity baru untuk penentuan izin aplikasi agar dapat berjalan otomatis.

Activity perizinan auto start pada perangkat Redmi Note X
Activity perizinan auto start pada perangkat Redmi Note X

Sebagai contoh, perangkat yang saya gunakan adalah Redmi Note X. Maka akan ditampilkan activity Mulai Otomatis (Auto Start). Hati-hati untuk memberikan izin untuk aplikasi yang meminta perizinan ini. Perizinan mulai otomatis akan membolehkan aplikasi berjalan otomatis saat perangkat dinyalakan ulang (reboot). Aplikasi tidak harus tampil pada layar perangkat, karena biasanya yang lebih dulu berjalan adalah program service yang dimiliki oleh aplikasi tersebut.

Aplikasi yang meminta izin mulai otomatis biasanya adalah aplikasi dengan yang mempunyai fitur jadwal harian. Misalnya aplikasi jadwal sholat yang mengharuskan menampilkan notofikasi azan setiap waktu shalat, aplikasi jual beli daring (online) untuk menginformasikan status pesanan barang, aplikasi berita harian, dan sebagainya. Izin mulai otomatis ini biasanya selalu ada pada aplikasi semacam ini, sehingga pengguna tidak perlu menjalankan aplikasi secara manual agar program service dari aplikasi ini dapat berjalan normal.

Aplikasi-aplikasi dengan fitur mulai otomatis harus mempunyai halaman kebijakan privasi saat akan dipasarkan di PlayStore. Termasuk aplikasi yang mewajibkan pengguna untuk membuat akun dan melakukan login ke aplikasi. Pastikan Anda sudah membaca kebijakan privasi yang diberikan dan memahami risikonya.