Skip to content
This repository was archived by the owner on Jul 11, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 66 additions & 6 deletions android/src/main/java/fr/g123k/deviceapps/DeviceAppsPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,33 @@ public void run() {
} else {
String packageName = call.argument("package_name").toString();
boolean includeAppIcon = call.hasArgument("include_app_icon") && (Boolean) (call.argument("include_app_icon"));

result.success(getApp(packageName, includeAppIcon));
}
break;

case "getAppByApkFiles":
// boolean includeAppIcons = call.hasArgument("include_app_icons") && (Boolean) (call.argument("include_app_icons"));
if (!call.hasArgument("paths")) {
result.error("ERROR", "Empty or invalid argument", null);
} else {
List<String> apkFilePaths = call.argument("paths");
boolean includeAppIcon = call.hasArgument("include_app_icon") && (Boolean) (call.argument("include_app_icon"));
// result.success(getAppByApkFile(apkFilePaths, includeAppIcon));
fetchApkIconsByFile(apkFilePaths, includeAppIcon, new InstalledAppsCallback() {
@Override
public void onInstalledAppsListAvailable(final List<Map<String, Object>> apps) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
result.success(apps);
}
});
}
});
}
break;

case "isAppInstalled":
if (!call.hasArgument("package_name") || TextUtils.isEmpty(call.argument("package_name").toString())) {
result.error("ERROR", "Empty or null package name", null);
Expand Down Expand Up @@ -127,6 +151,25 @@ public void run() {
});
}

//thread for getting apkIcons

private void fetchApkIconsByFile(final List<String> listOfPathsOfApkFiles, final boolean includeAppIcons, final InstalledAppsCallback callback) {
asyncWork.run(new Runnable() {

@Override
public void run() {
List<Map<String, Object>> installedApps = getAppByApkFile(listOfPathsOfApkFiles, includeAppIcons);

if (callback != null) {
callback.onInstalledAppsListAvailable(installedApps);
}
}

});
}



private List<Map<String, Object>> getInstalledApps(boolean includeSystemApps, boolean includeAppIcons, boolean onlyAppsWithLaunchIntent) {
PackageManager packageManager = context.getPackageManager();
List<PackageInfo> apps = packageManager.getInstalledPackages(0);
Expand All @@ -136,6 +179,7 @@ private List<Map<String, Object>> getInstalledApps(boolean includeSystemApps, bo
if (!includeSystemApps && isSystemApp(pInfo)) {
continue;
}

if (onlyAppsWithLaunchIntent && packageManager.getLaunchIntentForPackage(pInfo.packageName) == null) {
continue;
}
Expand All @@ -149,13 +193,11 @@ private List<Map<String, Object>> getInstalledApps(boolean includeSystemApps, bo

private boolean openApp(@NonNull String packageName) {
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);

// Null pointer check in case package name was not found
if (launchIntent != null) {
context.startActivity(launchIntent);
return true;
}

return false;
}

Expand All @@ -181,6 +223,27 @@ private Map<String, Object> getApp(String packageName, boolean includeAppIcon) {
}
}


// I am doing my stuff here...
// i want to get apkInfo from an apk file..
private List<Map<String, Object>> getAppByApkFile(List<String> listOfPathsOfApkFiles,boolean includeAppIcon) {
PackageManager packageManager = context.getPackageManager();
List<Map<String, Object>> apkFiles = new ArrayList<>(listOfPathsOfApkFiles.size());

for(String file : listOfPathsOfApkFiles) {
PackageInfo pi = packageManager.getPackageArchiveInfo(file, 0);

if(pi != null) {
pi.applicationInfo.sourceDir = file;
pi.applicationInfo.publicSourceDir = file;
Map<String, Object> map = getAppData(packageManager, pi, includeAppIcon);
apkFiles.add(map);
}
}

return apkFiles;
}

private Map<String, Object> getAppData(PackageManager packageManager, PackageInfo pInfo, boolean includeAppIcon) {
Map<String, Object> map = new HashMap<>();
map.put("app_name", pInfo.applicationInfo.loadLabel(packageManager).toString());
Expand All @@ -198,12 +261,9 @@ private Map<String, Object> getAppData(PackageManager packageManager, PackageInf
}

if (includeAppIcon) {
try {
Drawable icon = packageManager.getApplicationIcon(pInfo.packageName);
Drawable icon = pInfo.applicationInfo.loadIcon(packageManager);
String encodedImage = encodeToBase64(getBitmapFromDrawable(icon), Bitmap.CompressFormat.PNG, 100);
map.put("app_icon", encodedImage);
} catch (PackageManager.NameNotFoundException ignored) {
}
}

return map;
Expand Down
15 changes: 15 additions & 0 deletions example/ios/Flutter/flutter_export_environment.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/bin/sh
# This is a generated file; do not edit or check into version control.
export "FLUTTER_ROOT=E:\AndroidStudio\flutter"
export "FLUTTER_APPLICATION_PATH=C:\Users\FAISAL\Documents\GitHub\flutter_plugin_device_apps\example"
export "FLUTTER_TARGET=lib\main.dart"
export "FLUTTER_BUILD_DIR=build"
export "SYMROOT=${SOURCE_ROOT}/../build\ios"
export "OTHER_LDFLAGS=$(inherited) -framework Flutter"
export "FLUTTER_FRAMEWORK_DIR=E:\AndroidStudio\flutter\bin\cache\artifacts\engine\ios"
export "FLUTTER_BUILD_NAME=1.0.0"
export "FLUTTER_BUILD_NUMBER=1"
export "DART_OBFUSCATION=false"
export "TRACK_WIDGET_CREATION=false"
export "TREE_SHAKE_ICONS=false"
export "PACKAGE_CONFIG=.packages"
Comment on lines +1 to +15

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not be exposed in the version control, you can delete it by using git interactive rebase from you commits.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how can i change these

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just add the file name to .gitignore file or search in google to how to remove a file from a repository or how to add a file to .gitignore

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you the maintainer of this plugin

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you have knowledge flutter and native side communication because i want to collaborate with you i want to add some features and want to develop a plugin.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No I am not maintainer of this plugin, yes I have some knowledge of flutter and native code, I can help you if you want.

Copy link

@prateekmedia prateekmedia Apr 30, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are trying to develop a file manager you should also checkout FileX, jideguru has already done awesome work in it, if you want to contact me you can email me.

146 changes: 146 additions & 0 deletions lib/app_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import 'dart:convert';
import 'dart:typed_data';

enum ApplicationCategory {
/// Category for apps which primarily work with audio or music, such as
/// music players.
audio,

/// Category for apps which are primarily games.
game,

/// Category for apps which primarily work with images or photos, such as
/// camera or gallery apps.
image,

/// Category for apps which are primarily maps apps, such as navigation apps.
maps,

/// Category for apps which are primarily news apps, such as newspapers,
/// magazines, or sports apps.
news,

/// Category for apps which are primarily productivity apps, such as cloud
/// storage or workplace apps.
productivity,

/// Category for apps which are primarily social apps, such as messaging,
/// communication, email, or social network apps.
social,

/// Category for apps which primarily work with video or movies, such as
/// streaming video apps.
video,

/// Value when category is undefined.
undefined
}

class App {
final String appName;
final String apkFilePath;
final String packageName;
final String versionName;
final int versionCode;
final String dataDir;
final bool systemApp;
final int installTimeMillis;
final int updateTimeMillis;
final Uint8List appIcon;
final ApplicationCategory category;

App({
this.appIcon,
this.appName,
this.apkFilePath,
this.packageName,
this.versionName,
this.versionCode,
this.dataDir,
this.systemApp,
this.installTimeMillis,
this.updateTimeMillis,
this.category,
});

static List<App> fromList(List<Map<String, dynamic>> list) {
return List<App>.generate(list.length, (int i) {
final Map<dynamic, dynamic> map = list[i];
assert(map['app_name'] != null);
assert(map['apk_file_path'] != null);
assert(map['package_name'] != null);
assert(map['version_name'] != null);
assert(map['version_code'] != null);
assert(map['system_app'] != null);
assert(map['install_time'] != null);
assert(map['update_time'] != null);
if (map['app_icon'] != null) {
return App(
appName: map['app_name'],
apkFilePath: map['apk_file_path'],
packageName: map['package_name'],
versionName: map['version_name'],
versionCode: map['version_code'],
dataDir: map['data_dir'],
systemApp: map['system_app'],
installTimeMillis: map['install_time'],
updateTimeMillis: map['update_time'],
appIcon: base64Decode(map['app_icon']),
category: _parseCategory(map['category']));
} else {
return App(
appName: map['app_name'],
apkFilePath: map['apk_file_path'],
packageName: map['package_name'],
versionName: map['version_name'],
versionCode: map['version_code'],
dataDir: map['data_dir'],
systemApp: map['system_app'],
installTimeMillis: map['install_time'],
updateTimeMillis: map['update_time'],
category: _parseCategory(map['category'])
// appIcon: base64Decode(map['app_icon']),
);
}
});
}

static ApplicationCategory _parseCategory(Object category) {
if (category == null || (category is num && category < 0)) {
return ApplicationCategory.undefined;
} else if (category == 0) {
return ApplicationCategory.game;
} else if (category == 1) {
return ApplicationCategory.audio;
} else if (category == 2) {
return ApplicationCategory.video;
} else if (category == 3) {
return ApplicationCategory.image;
} else if (category == 4) {
return ApplicationCategory.social;
} else if (category == 5) {
return ApplicationCategory.news;
} else if (category == 6) {
return ApplicationCategory.maps;
} else if (category == 7) {
return ApplicationCategory.productivity;
} else {
return ApplicationCategory.undefined;
}
}

@override
String toString() {
return 'Application{'
'appName: $appName, '
'apkFilePath: $apkFilePath, '
'packageName: $packageName, '
'versionName: $versionName, '
'versionCode: $versionCode, '
'dataDir: $dataDir, '
'systemApp: $systemApp, '
'installTimeMillis: $installTimeMillis, '
'updateTimeMillis: $updateTimeMillis, '
'category: $category}';
}
}
53 changes: 24 additions & 29 deletions lib/device_apps.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,23 @@ class DeviceApps {
/// To get the icon you have to cast the object to [ApplicationWithIcon]
/// [onlyAppsWithLaunchIntent] will only list applications when an entrypoint.
/// It is similar to what a launcher will display
//

static Future<List<Application>> getInstalledApplications(
{bool includeSystemApps: false,
bool includeAppIcons: false,
bool onlyAppsWithLaunchIntent: false}) async {
return _channel.invokeMethod('getInstalledApps', <String, bool>{
'system_apps': includeSystemApps,
'include_app_icons': includeAppIcons,
'only_apps_with_launch_intent': onlyAppsWithLaunchIntent
}).then((Object apps) {
if (apps != null && apps is List) {
List<Application> list = List<Application>();
for (Object app in apps) {
if (app is Map) {
try {
list.add(Application._(app));
} catch (e) {
if (e is AssertionError) {
print('[DeviceApps] Unable to add the following app: $app');
} else {
print('[DeviceApps] $e');
}
}
}
}

return list;
} else {
return List<Application>(0);
}
}).catchError((Object err) {
print(err);
return List<Application>(0);
});
try {
final List data =
await _channel.invokeMethod('getInstalledApps', <String, bool>{
'system_apps': includeSystemApps,
'include_app_icons': includeAppIcons,
'only_apps_with_launch_intent': onlyAppsWithLaunchIntent
});
return data;
} catch (e) {
throw Exception(e);
}
}

/// Provide all information for a given app by its [packageName]
Expand Down Expand Up @@ -98,6 +82,17 @@ class DeviceApps {
return await _channel
.invokeMethod('openApp', <String, String>{'package_name': packageName});
}

// This return List<Map<String, dynamic>> you have a util class in this package called App which converts this List<Map> to List<App> you just need to do
// App.fromList(List list);
// that's it.
// here we are not doing this because if you want to parse this into a diffrent isolate you can do that.
// this is the benefit of not doing it here.
static Future<List> getAppByApkFile(List<String> list) async {
final List data = await _channel.invokeMethod(
'getAppByApkFiles', <String, List<String>>{'paths': list});
return data;
}
}

/// An application installed on the device
Expand Down