Show non-Zapstore installer package ID in app info.

Expose Android install-source package names so users can see when an app was installed from Play Store or another channel.
This commit is contained in:
franzap
2026-08-05 22:07:14 -03:00
parent df25892ae8
commit 0e4a6720ac
6 changed files with 43 additions and 1 deletions
@@ -1854,11 +1854,25 @@ class AndroidPackageManagerPlugin :
"versionName" to pkg.versionName,
"versionCode" to versionCode,
"signatureHashes" to getSignatureHashes(pkg.packageName),
"installerPackageName" to getInstallerPackageName(pkg.packageName),
"canInstallSilently" to canInstallSilently(pkg.packageName)
)
}
}
private fun getInstallerPackageName(packageName: String): String? {
return try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
context.packageManager.getInstallSourceInfo(packageName).installingPackageName
} else {
@Suppress("DEPRECATION")
context.packageManager.getInstallerPackageName(packageName)
}
} catch (_: Exception) {
null
}
}
private fun getSignatureHashes(packageName: String): List<String> {
return try {
val pm = context.packageManager
@@ -512,6 +512,8 @@ final class AndroidPackageManager extends PackageManager {
versionCode: target.versionCode,
signatureHashes: existingPkg?.signatureHashes ?? const [],
installTime: DateTime.now(),
installerPackageName:
existingPkg?.installerPackageName ?? kZapstoreAppIdentifier,
canInstallSilently: existingPkg?.canInstallSilently ?? false,
);
state = state.copyWith(installed: {...state.installed, appId: newPkg});
@@ -794,6 +796,7 @@ final class AndroidPackageManager extends PackageManager {
? rawHashes.cast<String>().toList()
: <String>[];
final canInstallSilently = app['canInstallSilently'] as bool? ?? false;
final installerPackageName = app['installerPackageName'] as String?;
if (canInstallSilently) anyCanInstallSilently = true;
@@ -805,6 +808,7 @@ final class AndroidPackageManager extends PackageManager {
versionCode: versionCode,
signatureHashes: signatureHashes,
installTime: null,
installerPackageName: installerPackageName,
canInstallSilently: canInstallSilently,
);
}
@@ -77,6 +77,7 @@ final class BackgroundPackageManager extends PackageManager {
? rawHashes.cast<String>().toList()
: const [],
installTime: null,
installerPackageName: app['installerPackageName'] as String?,
canInstallSilently: app['canInstallSilently'] as bool? ?? false,
);
}
@@ -26,6 +26,7 @@ class InstalledPackagesSnapshot {
'version': p.version,
'versionCode': p.versionCode,
'signatureHashes': p.signatureHashes,
'installerPackageName': p.installerPackageName,
'canInstallSilently': p.canInstallSilently,
},
)
@@ -87,6 +88,7 @@ class InstalledPackagesSnapshot {
versionCode: map['versionCode'] as int?,
signatureHashes: signatureHashes,
installTime: null,
installerPackageName: map['installerPackageName'] as String?,
canInstallSilently: (map['canInstallSilently'] as bool?) ?? false,
);
}
@@ -26,6 +26,7 @@ class PackageInfo extends Equatable {
this.signatureHashes = const [],
this.name,
this.installTime,
this.installerPackageName,
this.canInstallSilently = false,
});
@@ -35,6 +36,10 @@ class PackageInfo extends Equatable {
final int? versionCode;
final List<String> signatureHashes;
final DateTime? installTime;
/// Package ID of the app that installed this package, if known.
/// Examples: `dev.zapstore.app`, `com.android.vending` (Play Store).
final String? installerPackageName;
final bool canInstallSilently;
@override
@@ -45,6 +50,7 @@ class PackageInfo extends Equatable {
versionCode,
signatureHashes,
installTime,
installerPackageName,
canInstallSilently,
];
}
+16 -1
View File
@@ -5,6 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:intl/intl.dart';
import 'package:models/models.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:zapstore/services/package_manager/package_manager.dart';
import 'package:zapstore/utils/extensions.dart';
import 'package:zapstore/widgets/app_detail_widgets.dart';
import 'package:zapstore/widgets/author_container.dart';
@@ -86,6 +87,21 @@ class AppInfoTable extends HookConsumerWidget {
rows.add(_InfoRow(label: 'App ID', value: app.identifier));
final installedPackage = ref.watch(
installedPackageProvider(app.identifier),
);
final installerPackageName = installedPackage?.installerPackageName;
if (installerPackageName != null &&
installerPackageName != kZapstoreAppIdentifier) {
rows.add(
_InfoRow(
label: 'Installer',
value: installerPackageName,
copyValue: installerPackageName,
),
);
}
if (identityProof != null) {
final npub = Utils.encodeShareableFromString(
identityProof!.pubkey,
@@ -154,7 +170,6 @@ class AppInfoTable extends HookConsumerWidget {
}
if (fileMetadata!.versionCode != null) {
final installedPackage = app.installedPackage;
final installedVersionCode = installedPackage?.versionCode;
final availableVersionCode = fileMetadata!.versionCode!;