Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works

Random project

MBen.AndroidPermissions

A fluent, production-ready Android permissions management library for Delphi that provides intelligent manifest verification, detailed logging, and granular permission control for modern Android development.

View on GitHub

Anyone may press Interesting, signed in or not. It helps others find this project.

Member rating

No ratings yet.

Sign in to rate this project.

README

Android Permissions Management Library for Delphi

⚠️ BETA DEMO - This is a proof-of-concept library for educational and demonstration purposes. Not recommended for production use without thorough testing.

A fluent Android permissions management library for Delphi that provides intelligent manifest verification, detailed logging, and granular permission control.


🚀 Features

Ready-to-Use Methods

Configuration

  • SetLogger() - Inject logging callback

Permission Addition (3 Ways)

  • Fluent methods: .CAMERA.ACCESS_FINE_LOCATION... (type-safe)
  • AddPermission() - Dynamic single add (runtime)
  • AddPermissions() - Batch add from array

Permission Queries

  • GetGrantedPermissions() - All granted permissions
  • GetDeniedPermissions() - All denied/missing permissions
  • GetNotInManifestPermissions() - Permissions not in manifest
  • ToArray() - All added permissions

Execution

  • CheckAndRequest() - Execute complete check/verify/request process ⭐

Core Capabilities

  • ✅ Fluent API - Chain methods naturally
  • ✅ Manifest Verification - Auto-validates permissions exist in AndroidManifest.xml
  • ✅ Smart Sorting - Maintains manifest declaration order
  • ✅ 3-Phase Process - Manifest → Analysis → Request
  • ✅ Detailed Logging - Visual indicators (✓, ✗, ⏳, ⚠)
  • ✅ Denial Detection - Distinguishes manifest missing vs user rejected
  • ✅ Dynamic Support - Add new/future permissions at runtime
  • ✅ Thread-Safe - Safe UI updates via TThread.Queue
  • ✅ Zero Boilerplate - Single call handles everything

🔧 Installation

Step 1: Add Files

Copy to your project:

  • API.Android.Permissions.Interfaces.pas
  • API.Android.Permissions.pas

Step 2: Add Uses Clause

pascal
uses
  API.Android.Permissions.Interfaces,
  API.Android.Permissions;

Step 3: Declare in Form

pascal
type
  TMainView = class(TForm)
    MemoLog: TMemo;
  private
    FPermissions: iAndroidPermissions;
    procedure Log(const aMsg: string);
  end;

Step 4: AndroidManifest.xml

xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-sdk
        android:minSdkVersion="21"
        android:targetSdkVersion="35" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.CALL_PHONE" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" />
  
  <application>...</application>
</manifest>

💡 Quick Start

Basic Usage

pascal
procedure TMainView.FormCreate(Sender: TObject);
begin
  FPermissions := TAndroidPermissions.New
    .SetLogger(Log)
    .ACCESS_COARSE_LOCATION
    .ACCESS_FINE_LOCATION
    .CALL_PHONE
    .CAMERA
    .INTERNET
    .READ_EXTERNAL_STORAGE
    .READ_PHONE_STATE
    .WRITE_EXTERNAL_STORAGE
    .ACCESS_NETWORK_STATE  // Not in manifest - will be flagged
    .RECORD_AUDIO          // Not in manifest - will be flagged
    .READ_CONTACTS         // Not in manifest - will be flagged
    .SEND_SMS              // Not in manifest - will be flagged

    .CheckAndRequest(procedure(aAllGranted: Boolean; aGranted, aDenied: TArray<string>)
      begin
        if aAllGranted then
          Log('✓ All permissions granted - app is fully operational!');
//        // get only aGranted list ..
          Log('Granted list:');
          Log(GetLogPermissions(aGranted));
//        // get only aDenied List ..
          Log('Denied list:');
          Log(GetLogPermissions(aDenied));

        if IsPermGranted(cCAMERA) then
           Log('Camera is granted');

      end);
end;

procedure TMainView.Log(const aMsg: string);
begin
  TThread.Queue(nil,
    procedure
    begin
      MemoLog.Lines.Add(FormatDateTime('hh:nn:ss', Now) + ': ' + aMsg);
      // Auto-scroll to bottom
      if MemoLog.Lines.Count > 0 then
        MemoLog.GoToTextEnd;
    end);
end;

Check Individual Permissions

pascal
// Check after CheckAndRequest completes
if IsPermGranted(cCAMERA) then
  UseCameraFeatures()
else
  DisableCameraFeatures();

Three Ways to Add Permissions

Method 1: Fluent (Type-Safe)

pascal
FPermissions
  .CAMERA
  .ACCESS_FINE_LOCATION
  .RECORD_AUDIO;

Method 2: Dynamic Single

pascal
FPermissions.AddPermission('android.permission.CAMERA');

Method 3: Batch

pascal
FPermissions.AddPermissions([
  'android.permission.CAMERA',
  'android.permission.READ_MEDIA_IMAGES'
]);

Real-World Example

pascal
FPermissions := TAndroidPermissions.New
  .SetLogger(Log)
  .CAMERA
  .ACCESS_FINE_LOCATION
  .RECORD_AUDIO
  .CheckAndRequest(procedure(aAllGranted: Boolean; aGranted, aDenied: TArray<string>)
    begin
      // Enable features individually
      if IsPermGranted(cCAMERA) then
        BtnCamera.Enabled := True;
      
      if IsPermGranted(cACCESS_FINE_LOCATION) then
        BtnLocation.Enabled := True;
      
      if IsPermGranted(cRECORD_AUDIO) then
        BtnAudio.Enabled := True;
      
      // Log results
      Log('Granted: ' + IntToStr(Length(aGranted)));
      Log('Denied: ' + IntToStr(Length(aDenied)));
    end);

🎯 How It Works

Three-Phase Process

Phase 1: Manifest Verification

  • Reads AndroidManifest.xml
  • Lists all declared permissions
  • Validates requested permissions exist

Phase 2: Permission Analysis

  • Checks current grant status
  • Categorizes as: Granted, Pending, or Not-in-Manifest
  • Maintains manifest order
  • Prepares request list

Phase 3: System Request

  • Requests non-granted permissions
  • Shows rationale dialog if needed
  • Captures user responses
  • Logs results

📊 Example Log Output

pascal
02:21:27: 
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: ???    ANDROID PERMISSIONS CHECK AND REQUEST PROCESS          ???
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: 
02:21:27: This app uses the enhanced permissions system that:
02:21:27:   1. Verifies permissions exist in AndroidManifest.xml
02:21:27:   2. Checks current grant status
02:21:27:   3. Requests only missing permissions
02:21:27:   4. Logs detailed denial reasons
02:21:27:   5. Shows OS-level denial information
02:21:27: 
02:21:27:  Expected [Manifest.XML] Permissions At Runtime:
02:21:27: 
02:21:27:   ??? ACCESS_COARSE_LOCATION
02:21:27:   ??? ACCESS_FINE_LOCATION
02:21:27:   ??? CALL_PHONE
02:21:27:   ??? CAMERA
02:21:27:   ??? INTERNET
02:21:27:   ??? READ_EXTERNAL_STORAGE
02:21:27:   ??? READ_PHONE_STATE
02:21:27:   ??? WRITE_EXTERNAL_STORAGE
02:21:27: 
02:21:27: Application initialized. Ready to request permissions.
02:21:27: 
02:21:27:   Checking 12 permissions...
02:21:27: 
02:21:27: PHASE 1: MANIFEST VERIFICATION
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: Total permissions in manifest: 8
02:21:27: 
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: 
02:21:27: PHASE 2: PERMISSION STATUS ANALYSIS
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: Analyzing 12 requested permissions:
02:21:27: 
02:21:27:   ??? GRANTED: ACCESS_COARSE_LOCATION
02:21:27:   ??? GRANTED: ACCESS_FINE_LOCATION
02:21:27:   ??? GRANTED: CALL_PHONE
02:21:27:   ??? GRANTED: CAMERA
02:21:27:   ??? GRANTED: INTERNET
02:21:27:   ??? GRANTED: READ_EXTERNAL_STORAGE
02:21:27:   ??? GRANTED: READ_PHONE_STATE
02:21:27:   ??? GRANTED: WRITE_EXTERNAL_STORAGE
02:21:27:   ??? NOT_IN_MANIFEST: ACCESS_NETWORK_STATE
02:21:27:      ?????? Action: Add to AndroidManifest.xml
02:21:27:   ??? NOT_IN_MANIFEST: RECORD_AUDIO
02:21:27:      ?????? Action: Add to AndroidManifest.xml
02:21:27:   ??? NOT_IN_MANIFEST: READ_CONTACTS
02:21:27:      ?????? Action: Add to AndroidManifest.xml
02:21:27:   ??? NOT_IN_MANIFEST: SEND_SMS
02:21:27:      ?????? Action: Add to AndroidManifest.xml
02:21:27: 
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: ANALYSIS SUMMARY:
02:21:27:   Total Requested:    12
02:21:27:   Already Granted:    8
02:21:27:   Pending Request:    0
02:21:27:   Not in Manifest:    4
02:21:27: ???????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????????
02:21:27: 
02:21:27: ??? INCOMPLETE: Some permissions missing from manifest.
02:21:27: 
02:21:27: Required manifest declarations:
02:21:27:   <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
02:21:27:   <uses-permission android:name="android.permission.RECORD_AUDIO" />
02:21:27:   <uses-permission android:name="android.permission.READ_CONTACTS" />
02:21:27:   <uses-permission android:name="android.permission.SEND_SMS" />
02:21:27: 
02:21:27: ??? All permissions granted - app is fully operational!
02:21:27: Granted list:
02:21:27: 
android.permission.ACCESS_COARSE_LOCATION
android.permission.ACCESS_FINE_LOCATION
android.permission.CALL_PHONE
android.permission.CAMERA
android.permission.INTERNET
android.permission.READ_EXTERNAL_STORAGE
android.permission.READ_PHONE_STATE
android.permission.WRITE_EXTERNAL_STORAGE
02:21:27: Denied list:
02:21:27: 
android.permission.ACCESS_NETWORK_STATE
android.permission.RECORD_AUDIO
android.permission.READ_CONTACTS
android.permission.SEND_SMS
02:21:27: Camera is granted

🛠️ Helper Functions

Global Utilities

pascal
// Quick permission check
IsPermGranted(cCAMERA): Boolean

// Format permissions for logging
GetLogPermissions(aPerms: TArray<string>): string

Usage

pascal
if IsPermGranted(cCAMERA) then
  Log('Camera available');

var Perms := FPermissions.GetGrantedPermissions;
Log('Granted:' + GetLogPermissions(Perms));

📚 API Reference

Interface: iAndroidPermissions

pascal
interface iAndroidPermissions
  function SetLogger(const aLogger: TLoggerProc): iAndroidPermissions;
  
  // 200+ fluent permission methods
  function CAMERA: iAndroidPermissions;
  function ACCESS_FINE_LOCATION: iAndroidPermissions;
  // ... etc
  
  function AddPermission(const aPermission: string): iAndroidPermissions;
  function AddPermissions(const aPermissions: TArray<string>): iAndroidPermissions;
  
  function ToArray: TArray<string>;
  function GetGrantedPermissions: TArray<string>;
  function GetDeniedPermissions: TArray<string>;
  function GetNotInManifestPermissions: TArray<string>;
  
  function CheckAndRequest(const aOnResult: TPermissionResultProc = nil): iAndroidPermissions;
end;

Callback Type

pascal
TPermissionResultProc = TProc<Boolean, TArray<string>, TArray<string>>;
// Parameters:
// - aAllGranted: All permissions granted?
// - aGranted: Granted permissions array
// - aDenied: Denied/missing permissions array

Permission Constants

pascal
cCAMERA = 'android.permission.CAMERA';
cACCESS_FINE_LOCATION = 'android.permission.ACCESS_FINE_LOCATION';
cREAD_CONTACTS = 'android.permission.READ_CONTACTS';
// ... 197+ more constants

🗺️ Roadmap

Version 1.0 (Current - Beta)

  • ✅ Core permission management
  • ✅ Fluent API with 200+ methods
  • ✅ Manifest verification
  • ✅ 3-phase process
  • ✅ Detailed logging

How to Report

Include:

  1. Android version and device model
  2. Delphi version
  3. Permissions requested
  4. Expected vs actual behavior
  5. Complete log output
  6. Reproduction steps

📄 License

MIT License - Free to use, modify, and distribute

  • Include license notice
  • No liability accepted

🎓 Use Cases

  • ✅ Educational demonstration
  • ✅ Proof-of-concept projects
  • ✅ Development and testing
  • ✅ Reference implementation
  • ⚠️ Production (test thoroughly first)

🤝 Contributing

  • Test on multiple Android versions
  • Report issues with full details
  • Share improvements
  • Suggest enhancements

⭐ Demonstration Library - Testing & Feedback Welcome


Version: 1.0.0-beta
Last Updated: January 2026
Status: BETA - Proof of Concept