Comment obtenir le nom du package de n'importe où?

346

Je suis conscient de la disponibilité de Context.getApplicationContext () et View.getContext () , à travers lequel je peux réellement appeler Context.getPackageName () pour récupérer le nom de package d'une application.

Ils fonctionnent si j'appelle à partir d'une méthode à laquelle un Viewou un Activityobjet est disponible, mais si je veux trouver le nom du package dans une classe totalement indépendante sans Viewou Activity, existe-t-il un moyen de le faire (directement ou indirectement)?

ef2011
la source
7
Une réponse acceptée entraînera occasionnellement le CRASH de votre application - lisez les commentaires d'AddDev & Turbo et merci à eux deux d'avoir suggéré des solutions.
nikib3ro
1
Vous n'avez peut-être pas d'autre option, mais dans le cadre des meilleures pratiques, je dirais qu'il est préférable de transmettre cela à la classe dans laquelle vous en avez besoin à partir de votre dernier point de contexte d'une manière ou d'une autre. Vous accédez aux informations de contexte d'exécution à partir d'une classe qui ne connaît pas les contextes de manière statique - ça me sent mauvais. Une autre approche serait de le coder en dur quelque part.
Adam

Réponses:

488

Une idée est d'avoir une variable statique dans votre activité principale, instanciée pour être le nom du package. Il suffit ensuite de référencer cette variable.

Vous devrez l'initialiser dans la onCreate()méthode de l'activité principale :

Global à la classe:

public static String PACKAGE_NAME;

Alors..

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    PACKAGE_NAME = getApplicationContext().getPackageName();
}

Vous pouvez ensuite y accéder via Main.PACKAGE_NAME.

John Leehey
la source
3
Cela semble être la solution la plus pratique pour moi en ce moment, mais cela nécessite que je crée une sous-classe de l'activité ... +1 pour l'instant.
ef2011
1
Je viens de trouver une référence similaire: stackoverflow.com/questions/2002288/…
ef2011
13
Ma compréhension est que finalcela le rend immuable, initialisable uniquement dans un constructeur et une seule fois . onCreate()n'est pas un constructeur. Veuillez corriger si je me trompe.
ef2011
79
Cette approche est incorrecte. Par exemple, si votre application passe en arrière-plan lorsque vous êtes sur une activité secondaire, puis est restaurée. Impossible d'appeler onCreate () de votre activité principale et votre PACKAGE_NAME sera nul !. De plus, que se passe-t-il si votre application a 10 points d'entrée et qu'il n'y a pas une "activité principale" claire? Vous pouvez vérifier ma réponse à cette question pour la bonne approche
Addev
3
@Turbo, si Android tue le processus, onCreatedevra être rappelé de toute façon, donc cette solution ne devrait toujours pas poser de problème.
John Leehey
276

Si vous utilisez le plugin gradle-android pour créer votre application, vous pouvez utiliser

BuildConfig.APPLICATION_ID

pour récupérer le nom du package à partir de n'importe quelle étendue, incl. statique.

Billda
la source
23
C'est la bonne façon, devrait être la réponse acceptée.
aberaud
4
Remarque: Avec les versions multi-saveurs, cela renverra (en fonction de l'importation utilisée pour accéder à la classe BuildConfig) le nom de package de la configuration par défaut et non le nom de package de la version.
Rolf
2
@Rolf ツ Ce n'est pas vrai, il renverra le bon nom de package d'application;) peut-être le
confondez
28
Soyez prudent si vous l'utilisez dans un projet de bibliothèque - cela ne fonctionnera pas.
zyamys
6
Soyez prudent si vous l'utilisez également dans plusieurs modules d'un projet.
user802421
68

Si avec le mot "n'importe où" vous voulez dire sans avoir un explicite Context(par exemple à partir d'un fil d'arrière-plan), vous devez définir une classe dans votre projet comme:

public class MyApp extends Application {
    private static MyApp instance;

    public static MyApp getInstance() {
        return instance;
    }

    public static Context getContext(){
        return instance;
        // or return instance.getApplicationContext();
    }

    @Override
    public void onCreate() {
        instance = this;
        super.onCreate();
    }
}

Ensuite, dans votre, manifestvous devez ajouter cette classe au Namechamp de l' Applicationonglet. Ou éditez le xml et mettez

<application
    android:name="com.example.app.MyApp"
    android:icon="@drawable/icon"
    android:label="@string/app_name"
    .......
    <activity
        ......

puis de n'importe où vous pouvez appeler

String packagename= MyApp.getContext().getPackageName();

J'espère que cela aide.

Addev
la source
Ce n'est pas sûr pour les threads, mais vous pouvez probablement vous en sortir si le thread d'arrière-plan est démarré par cette activité plus tard.
tomwhipple
3
Il est thread-safe car la référence à l'instance est la première chose définie lorsque l'application est lancée
Addev
17
Par ce problème: code.google.com/p/android/issues/detail?id=8727 Les objets ContentProvider sont créés avant l'objet Application, apparemment contraire à la documentation, mais aussi apparemment par et selon la conception. Cela pourrait entraîner la non-définition de votre instance si getInstance () était appelée lors de l'initialisation d'un ContentProvider.
Carl
3
La documentation sur Application.onCreate()a été modifiée pour refléter cela: elle indique désormais spécifiquement "Appelé au démarrage de l'application, avant toute activité, service ou objet récepteur (à l'exclusion des fournisseurs de contenu)".
Paul Lammertsma
2
Cela devrait être la réponse choisie, car le contexte ne s'éteindra jamais, quelle que soit l'activité en cours.
Elad Nava
43

Si vous utilisez la construction gradle, utilisez ceci: BuildConfig.APPLICATION_IDpour obtenir le nom du package de l'application.

Mahendra Liya
la source
6
L'ID d'application et le nom du package sont des choses différentes. L'ID d'application est défini via le fichier gradle.build et le nom du package est défini dans le manifeste. Bien qu'ils aient souvent la même valeur, ils diffèrent également souvent, dans des scénarios de construction plus complexes. On peut attribuer différents ID d'application à différentes configurations de build tandis que le nom du package reste inchangé.
Uli
3
@Uli Pour ceux qui veulent connaître les nuances un peu plus en détail tools.android.com/tech-docs/new-build-system/…
Kevin Lee
10
@Uli Cela étant dit, même si l'applicationId dans app.gradle diffère du packageName à l'intérieur du fichier AndroidManifest.xml, l'appel context.getPackageName () renvoie le applicationId et non le packageName à l'intérieur d'AndroidManifest.xml. Le but du nouveau système de construction était de découpler les deux, donc applicationId est le nom de package réel de l'application connu de Google Play et de l'appareil sur lequel il est installé - il ne peut pas changer après le déploiement. Mon point est, il est correct d'utiliser BuildConfig.APPLICATION_ID. Faites-moi savoir si je me trompe (:
Kevin Lee
2
@kevinze Entièrement précis! J'ai effectué un test pour revérifier. Merci pour la clarification / correction.
Uli
5
private String getApplicationName(Context context, String data, int flag) {

   final PackageManager pckManager = context.getPackageManager();
   ApplicationInfo applicationInformation;
   try {
       applicationInformation = pckManager.getApplicationInfo(data, flag);
   } catch (PackageManager.NameNotFoundException e) {
       applicationInformation = null;
   }
   final String applicationName = (String) (applicationInformation != null ? pckManager.getApplicationLabel(applicationInformation) : "(unknown)");
   return applicationName;

}
bala7s
la source
4

Vous pouvez obtenir le nom de votre package comme suit:

$ /path/to/adb shell 'pm list packages -f myapp'
package:/data/app/mycompany.myapp-2.apk=mycompany.myapp

Voici les options:

$ adb
Android Debug Bridge version 1.0.32
Revision 09a0d98bebce-android

 -a                            - directs adb to listen on all interfaces for a connection
 -d                            - directs command to the only connected USB device
                                 returns an error if more than one USB device is present.
 -e                            - directs command to the only running emulator.
                                 returns an error if more than one emulator is running.
 -s <specific device>          - directs command to the device or emulator with the given
                                 serial number or qualifier. Overrides ANDROID_SERIAL
                                 environment variable.
 -p <product name or path>     - simple product name like 'sooner', or
                                 a relative/absolute path to a product
                                 out directory like 'out/target/product/sooner'.
                                 If -p is not specified, the ANDROID_PRODUCT_OUT
                                 environment variable is used, which must
                                 be an absolute path.
 -H                            - Name of adb server host (default: localhost)
 -P                            - Port of adb server (default: 5037)
 devices [-l]                  - list all connected devices
                                 ('-l' will also list device qualifiers)
 connect <host>[:<port>]       - connect to a device via TCP/IP
                                 Port 5555 is used by default if no port number is specified.
 disconnect [<host>[:<port>]]  - disconnect from a TCP/IP device.
                                 Port 5555 is used by default if no port number is specified.
                                 Using this command with no additional arguments
                                 will disconnect from all connected TCP/IP devices.

device commands:
  adb push [-p] <local> <remote>
                               - copy file/dir to device
                                 ('-p' to display the transfer progress)
  adb pull [-p] [-a] <remote> [<local>]
                               - copy file/dir from device
                                 ('-p' to display the transfer progress)
                                 ('-a' means copy timestamp and mode)
  adb sync [ <directory> ]     - copy host->device only if changed
                                 (-l means list but don't copy)
  adb shell                    - run remote shell interactively
  adb shell <command>          - run remote shell command
  adb emu <command>            - run emulator console command
  adb logcat [ <filter-spec> ] - View device log
  adb forward --list           - list all forward socket connections.
                                 the format is a list of lines with the following format:
                                    <serial> " " <local> " " <remote> "\n"
  adb forward <local> <remote> - forward socket connections
                                 forward specs are one of:
                                   tcp:<port>
                                   localabstract:<unix domain socket name>
                                   localreserved:<unix domain socket name>
                                   localfilesystem:<unix domain socket name>
                                   dev:<character device name>
                                   jdwp:<process pid> (remote only)
  adb forward --no-rebind <local> <remote>
                               - same as 'adb forward <local> <remote>' but fails
                                 if <local> is already forwarded
  adb forward --remove <local> - remove a specific forward socket connection
  adb forward --remove-all     - remove all forward socket connections
  adb reverse --list           - list all reverse socket connections from device
  adb reverse <remote> <local> - reverse socket connections
                                 reverse specs are one of:
                                   tcp:<port>
                                   localabstract:<unix domain socket name>
                                   localreserved:<unix domain socket name>
                                   localfilesystem:<unix domain socket name>
  adb reverse --norebind <remote> <local>
                               - same as 'adb reverse <remote> <local>' but fails
                                 if <remote> is already reversed.
  adb reverse --remove <remote>
                               - remove a specific reversed socket connection
  adb reverse --remove-all     - remove all reversed socket connections from device
  adb jdwp                     - list PIDs of processes hosting a JDWP transport
  adb install [-lrtsdg] <file>
                               - push this package file to the device and install it
                                 (-l: forward lock application)
                                 (-r: replace existing application)
                                 (-t: allow test packages)
                                 (-s: install application on sdcard)
                                 (-d: allow version code downgrade)
                                 (-g: grant all runtime permissions)
  adb install-multiple [-lrtsdpg] <file...>
                               - push this package file to the device and install it
                                 (-l: forward lock application)
                                 (-r: replace existing application)
                                 (-t: allow test packages)
                                 (-s: install application on sdcard)
                                 (-d: allow version code downgrade)
                                 (-p: partial application install)
                                 (-g: grant all runtime permissions)
  adb uninstall [-k] <package> - remove this app package from the device
                                 ('-k' means keep the data and cache directories)
  adb bugreport                - return all information from the device
                                 that should be included in a bug report.

  adb backup [-f <file>] [-apk|-noapk] [-obb|-noobb] [-shared|-noshared] [-all] [-system|-nosystem] [<packages...>]
                               - write an archive of the device's data to <file>.
                                 If no -f option is supplied then the data is written
                                 to "backup.ab" in the current directory.
                                 (-apk|-noapk enable/disable backup of the .apks themselves
                                    in the archive; the default is noapk.)
                                 (-obb|-noobb enable/disable backup of any installed apk expansion
                                    (aka .obb) files associated with each application; the default
                                    is noobb.)
                                 (-shared|-noshared enable/disable backup of the device's
                                    shared storage / SD card contents; the default is noshared.)
                                 (-all means to back up all installed applications)
                                 (-system|-nosystem toggles whether -all automatically includes
                                    system applications; the default is to include system apps)
                                 (<packages...> is the list of applications to be backed up.  If
                                    the -all or -shared flags are passed, then the package
                                    list is optional.  Applications explicitly given on the
                                    command line will be included even if -nosystem would
                                    ordinarily cause them to be omitted.)

  adb restore <file>           - restore device contents from the <file> backup archive

  adb disable-verity           - disable dm-verity checking on USERDEBUG builds
  adb enable-verity            - re-enable dm-verity checking on USERDEBUG builds
  adb keygen <file>            - generate adb public/private key. The private key is stored in <file>,
                                 and the public key is stored in <file>.pub. Any existing files
                                 are overwritten.
  adb help                     - show this help message
  adb version                  - show version num

scripting:
  adb wait-for-device          - block until device is online
  adb start-server             - ensure that there is a server running
  adb kill-server              - kill the server if it is running
  adb get-state                - prints: offline | bootloader | device
  adb get-serialno             - prints: <serial-number>
  adb get-devpath              - prints: <device-path>
  adb remount                  - remounts the /system, /vendor (if present) and /oem (if present) partitions on the device read-write
  adb reboot [bootloader|recovery]
                               - reboots the device, optionally into the bootloader or recovery program.
  adb reboot sideload          - reboots the device into the sideload mode in recovery program (adb root required).
  adb reboot sideload-auto-reboot
                               - reboots into the sideload mode, then reboots automatically after the sideload regardless of the result.
  adb sideload <file>          - sideloads the given package
  adb root                     - restarts the adbd daemon with root permissions
  adb unroot                   - restarts the adbd daemon without root permissions
  adb usb                      - restarts the adbd daemon listening on USB
  adb tcpip <port>             - restarts the adbd daemon listening on TCP on the specified port

networking:
  adb ppp <tty> [parameters]   - Run PPP over USB.
 Note: you should not automatically start a PPP connection.
 <tty> refers to the tty for PPP stream. Eg. dev:/dev/omap_csmi_tty1
 [parameters] - Eg. defaultroute debug dump local notty usepeerdns

adb sync notes: adb sync [ <directory> ]
  <localdir> can be interpreted in several ways:

  - If <directory> is not specified, /system, /vendor (if present), /oem (if present) and /data partitions will be updated.

  - If it is "system", "vendor", "oem" or "data", only the corresponding partition
    is updated.

environment variables:
  ADB_TRACE                    - Print debug information. A comma separated list of the following values
                                 1 or all, adb, sockets, packets, rwx, usb, sync, sysdeps, transport, jdwp
  ANDROID_SERIAL               - The serial number to connect to. -s takes priority over this if given.
  ANDROID_LOG_TAGS             - When used with the logcat option, only these debug tags are printed.
user8128167
la source
3

Vous pouvez utiliser une méthode non documentéeandroid.app.ActivityThread.currentPackageName() :

Class<?> clazz = Class.forName("android.app.ActivityThread");
Method method  = clazz.getDeclaredMethod("currentPackageName", null);
String appPackageName = (String) method.invoke(clazz, null);

Attention: cela doit être fait sur le thread principal de l'application.

Merci à ce billet de blog pour l'idée: http://blog.javia.org/static-the-android-application-package/ .

Alexei Khlebnikov
la source
2

Pour ceux qui utilisent Gradle, comme @Billda l'a mentionné, vous pouvez obtenir le nom du package via:

BuildConfig.APPLICATION_ID

Cela vous donne le nom du package déclaré dans votre gradle d'application:

android {
    defaultConfig {
        applicationId "com.domain.www"
    }
}

Si vous souhaitez obtenir le nom du package utilisé par vos classes java (qui est parfois différent de applicationId), vous pouvez utiliser

BuildConfig.class.getPackage().toString()

Si vous ne savez pas lequel utiliser, lisez ici :

Remarque: L'ID d'application était auparavant directement lié au nom de package de votre code; certaines API Android utilisent donc le terme "nom de package" dans leurs noms de méthode et de paramètre, mais il s'agit en fait de votre ID d'application. Par exemple, la méthode Context.getPackageName () renvoie votre ID d'application. Il n'est pas nécessaire de partager le vrai nom de package de votre code en dehors du code de votre application.

user1506104
la source
quel code avez-vous utilisé? veuillez fournir l'erreur exacte que vous avez obtenue.
user1506104
1
PackageInfo pinfo = this.getPackageManager().getPackageInfo(getPackageName(), 0);
         String sVersionCode = pinfo.versionCode; // 1
         String sVersionName = pinfo.versionName; // 1.0
         String sPackName = getPackageName(); // cz.okhelp.my_app
         int nSdkVersion = Integer.parseInt(Build.VERSION.SDK); 
         int nSdkVers = Build.VERSION.SDK_INT; 

J'espère que cela fonctionnera.

Juboraj Sarker
la source
0

Créez un module java à exécuter initialement lors du démarrage de votre application. Ce module étendrait la classe d'application Android et initialiserait toutes les variables d'application globales et contiendrait également des routines utilitaires à l'échelle de l'application -

public class MyApplicationName extends Application {

    private final String PACKAGE_NAME = "com.mysite.myAppPackageName";

    public String getPackageName() { return PACKAGE_NAME; }
}

Bien sûr, cela pourrait inclure une logique pour obtenir le nom du package à partir du système Android; cependant, le code ci-dessus est plus petit, plus rapide et plus propre que celui obtenu auprès d'Android.

Assurez-vous de placer une entrée dans votre fichier AndroidManifest.xml pour indiquer à Android d'exécuter votre module d'application avant d'exécuter des activités -

<application 
    android:name=".MyApplicationName" 
    ...
>

Ensuite, pour obtenir le nom du package à partir de tout autre module, entrez

MyApp myApp = (MyApp) getApplicationContext();
String myPackage = myApp.getPackageName();

L'utilisation d'un module d'application vous donne également un contexte pour les modules qui ont besoin mais n'ont pas de contexte.

Earl Allen
la source
0

Utilisez: BuildConfig.APPLICATION_ID pour obtenir le NOM DU PAQUET n'importe où (c'est-à-dire les services, le récepteur, l'activité, le fragment, etc.)

Exemple: String PackageName = BuildConfig.APPLICATION_ID;

pharid
la source
0

Importez simplement Android.app ,, vous pourrez alors utiliser: <br/>Application.getProcessName()<br/>

Obtenez le nom du processus d'application actuel sans contexte, vue ou activité.

sans titre
la source