Unlocking the Secrets: How to Display All Applications with Access to Specific Permissions in Flutter

Muhamad Zulfa Assyfa
4 min readFeb 13, 2023

--

As a flutter developer, you may have come across the need to access information about other installed applications on the device, particularly their permission usage. One use case could be to display a list of all the applications that have access to the camera, contacts, or location, etc.

In this article, we will be discussing how to display all the applications that have access to certain application permissions using flutter, platform channels, and dart packages. We will be using the installed_apps package, version 1.3.1.

First, we will create a new flutter project and add the installed_apps package to the pubspec.yaml file.

dependencies:
flutter:
sdk: flutter
installed_apps: ^1.3.1

Next, in the main.dart file, we will import the installed_apps package and use the installedApps method to retrieve a list of all the installed applications.

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:installed_apps/app_info.dart';
import 'package:installed_apps/installed_apps.dart';

void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MainPage(),
);
}
}

class MainPage extends StatefulWidget {
const MainPage({Key? key}) : super(key: key);

@override
State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
static const platform =
MethodChannel('com.mzulfaas.package_manager');

List loadAppsList = [];
List<AppInfo> apps = [];

Future<void> loadApps() async {
try {
final result = await platform.invokeMethod('getApplicationInstalledInfo');
setState(() {
loadAppsList = result;
});
for (var i = 0; i < result.length; i++) {
apps.add(await InstalledApps.getAppInfo(result[i]['packageName']));
setState(() {});
}
// });
} on PlatformException catch (e) {
print("message :${e.message}");
}
print("callApps length :${loadAppsList.length}");
}

@override
void initState() {
super.initState();
loadApps();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(
"Demo",
),
),
body: ListView.builder(
itemCount: apps.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.transparent,
child: apps[index].icon != null
? Image.memory(apps[index].icon!)
: null,
),
title: Text("${apps[index].name}"),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("${apps[index].packageName}"),
Text("${loadAppsList[index]["permissionUsedByApplication"]}".replaceAll("_", " ").split('.').last),
],
),
),
);
}),
);
}
}

This code is a Flutter app that displays a list of all installed apps on an Android device. It makes use of a Method Channel to access information about installed apps from the native side, using the com.mzulfaas.package_manager channel. The information is then displayed in a list view with each item showing the app's name, package name, and permission used by the app. The loadApps function retrieves the list of installed apps and updates the app's state with the information. The ListView.builder widget is then used to display the applications in a scrollable list, with each application displayed as a ListTile widget with its name, package name, and icon.

To access specific permission usage information, we will need to use platform channels to access the native Android or iOS code. In this example, we will be accessing the Android code.

First, we’ll modify the Kotlin class in MainActivity.kt. We’ll use the MethodChannel class to create a channel to communicate with the flutter side of the code.

package com.mzulfaas.package_manager
import android.content.pm.PackageManager
import android.util.Log
import androidx.annotation.NonNull
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.embedding.android.FlutterActivity

class MainActivity: FlutterActivity() {
private val CHANNEL = "com.mzulfaas.package_manager"

override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getApplicationInstalledInfo") {
result.success(getApplicationInstalledInfo())
} else {
result.notImplemented()
}
}
}

private fun getApplicationInstalledInfo(): List<Map<String, String>> {
val p: PackageManager = this.getPackageManager()
val appinstall = p.getInstalledPackages(
PackageManager.GET_PERMISSIONS or PackageManager.GET_RECEIVERS or
PackageManager.GET_SERVICES or PackageManager.GET_PROVIDERS or PackageManager.GET_META_DATA
)
val installedApps = mutableListOf<Map<String,String>>()
for (pInfo in appinstall) {
val reqPermission = pInfo.requestedPermissions
if (reqPermission != null) {
for (i in reqPermission.indices) {
if (reqPermission[i].equals("android.permission.CAMERA") ||
reqPermission[i].equals("android.permission.READ_CONTACTS") ||
reqPermission[i].equals("android.permission.WRITE_CONTACTS") ||
reqPermission[i].equals("android.permission.ACCESS_FINE_LOCATION") ||
reqPermission[i].equals("android.permission.ACCESS_COARSE_LOCATION")) {
Log.d(
"Installed Applications with CAMERA/CONTACT/LOCATION permission", pInfo.applicationInfo
.loadLabel(p).toString()
)
Log.d("packageName", pInfo.packageName.toString())
installedApps.add(mapOf("packageName" to pInfo.packageName, "name" to pInfo.applicationInfo.loadLabel(p).toString(), "permissionUsedByApplication" to reqPermission[i]))
Log.d("intaslledApps", installedApps.toString())
}
}
}
}
return installedApps
}
}

With these modifications, we have successfully implemented the platform channel in Flutter to access the native Android code. The result is a list of all the installed applications and their specific permissions usage information.

Now that we have the permission usage information from the Android side of our application, we can use it to build interesting and useful features for our users. For instance, we can use this information to display a list of all the apps installed on the device that use the camera permission. This can be especially useful for users who are privacy conscious and want to know which apps on their device are accessing their camera.

Similarly, we can use the information to display a list of all the apps installed on the device that use the location permission. This can be useful for users who want to know which apps on their device are accessing their location information.

By providing this information to our users, we can help them make informed decisions about which apps they want to use and which apps they don’t. They can then choose to either keep the apps they trust and use frequently or remove the ones they don’t need or are suspicious of.

It is important to note that accessing this information requires the user’s permission and should be done with care. Users expect privacy and security, and we must ensure that we respect their privacy by using this information only for the purpose of providing them with helpful information.

In conclusion, accessing specific permission usage information on Android or iOS is a powerful tool that can be used to build useful and interesting features for users. By using platform channels, we can access the native code of the platform and get the information we need to build these features. With the information, we can help users make informed decisions about the apps they use and protect their privacy at the same time.

--

--

Muhamad Zulfa Assyfa
Muhamad Zulfa Assyfa

Written by Muhamad Zulfa Assyfa

I write these for myself || self-upgrade on progress..

No responses yet