14

Recently i was doing some research work on Android Dependencies and one question stuck on my mind. Question is can we get list of dependencies by using java code?

For example dependencies in my build.gradle file

dependencies {
   compile 'com.google.android.gms:play-services:+'
   compile 'com.facebook.android:facebook-android-sdk:4.1.0'
}

Now if i want name of those dependencies while the app is running, can we get it?

Ravi
  • 34,851
  • 21
  • 122
  • 183

2 Answers2

4

Not really. They are compile-time dependencies. In your compiled APK, there is no significant difference between:

  • compile 'com.facebook.android:facebook-android-sdk:4.1.0'

  • compile project(':facebook'), where you cloned a GitHub repo or something to give you a local library project as opposed to referencing an artifact from a repository

  • having a bunch of classes with Facebook's name and package in your app that you wrote (ditto a bunch of resources)

If you are writing the app, and you are using different build types and/or product flavors, and you have different dependencies for each, you can use BuildConfig to detect which build variant you are running.

If you are writing a library, and you want to determine at runtime if the developer added a certain dependency, the best you can do is sniff around to see if certain things exist from that dependency and if they match your expectations. The details for this will vary by dependency (e.g., seeing if Play Services exists would have one set of hard-coded checks; seeing if the Facebook SDK exists would have a separate set of hard-coded checks). This will not distinguish between my three bullets above, but it is the best that you are going to be able to do.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • yes that is what i am trying to do, writing one library and want to know what other dependecy developer have added. – Ravi Jan 04 '16 at 12:36
1

To put some code to @CommonsWare's comments about finding jar dependencies at runtime

import org.kohsuke.args4j.CmdLineParser;

import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;

public class RuntimeDependenciesExample {

    public static void main(String[] args) {
        // just to add some dependency for our list
        CmdLineParser parser = null;
        RuntimeDependenciesExample main = new RuntimeDependenciesExample();
        main.findRuntimeDependencies();
        main.checkSystemClassPath();
    }

    private void checkSystemClassPath() {
        System.out.println("System classpath:\n" + System.getProperty("java.class.path").replace(':', '\n'));
    }

    private void findRuntimeDependencies() {
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        do {
            System.out.println("Using classloader: " + classloader.toString());
            URL[] urls = ((URLClassLoader) classloader).getURLs();
            List<String> jars = new ArrayList<>();
            for (URL url : urls) {
                jars.add(url.getFile());
            }

            printFiltered(jars);
            classloader = classloader.getParent();
        } while (classloader != null);
    }

    private void printFiltered(List<String> jars) {
        System.out.println("\nFiltered jar list:");
        for (String jarPath : jars) {
            if (!jarPath.contains("jre") && !jarPath.contains("jdk")) {
                System.out.println(jarPath);
            }
        }
        System.out.println('\n');
    }
}

Could output something like this, which you could get the jar list:

Using classloader: sun.misc.Launcher$AppClassLoader@29453f44

Filtered jar list:
/Users/someUser/dev/test-code/build/classes/main/
/Users/someUser/dev/test-code/build/resources/main/
/Users/someUser/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy-all/2.3.11/f6b34997d04c1538ce451d3955298f46fdb4dbd4/groovy-all-2.3.11.jar
/Users/someUser/.gradle/caches/modules-2/files-2.1/args4j/args4j/2.32/1ccacebdf8f2db750eb09a402969050f27695fb7/args4j-2.32.jar
/Applications/IntelliJ%20IDEA%2016%20EAP.app/Contents/lib/idea_rt.jar


Using classloader: sun.misc.Launcher$ExtClassLoader@266474c2

Filtered jar list:
/usr/local/Cellar/subversion/1.8.10_2/lib/libsvnjavahl-1.0.dylib
/System/Library/Java/Extensions/MRJToolkit.jar


System classpath:
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/charsets.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/deploy.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/cldrdata.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/dnsns.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/jaccess.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/jfxrt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/localedata.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/nashorn.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/sunec.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/ext/zipfs.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/javaws.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/jce.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/jfr.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/jfxswt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/jsse.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/management-agent.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/plugin.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/resources.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/jre/lib/rt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/ant-javafx.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/dt.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/javafx-mx.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/jconsole.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/packager.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/sa-jdi.jar
/Library/Java/JavaVirtualMachines/jdk1.8.0_65.jdk/Contents/Home/lib/tools.jar
/Users/someUser/dev/test-code/build/classes/main
/Users/someUser/dev/test-code/build/resources/main
/Users/someUser/.gradle/caches/modules-2/files-2.1/org.codehaus.groovy/groovy-all/2.3.11/f6b34997d04c1538ce451d3955298f46fdb4dbd4/groovy-all-2.3.11.jar
/Users/someUser/.gradle/caches/modules-2/files-2.1/args4j/args4j/2.32/1ccacebdf8f2db750eb09a402969050f27695fb7/args4j-2.32.jar
/Applications/IntelliJ IDEA 16 EAP.app/Contents/lib/idea_rt.jar
JBirdVegas
  • 10,855
  • 2
  • 44
  • 50
  • `main`? that would be for a java app, not an android app. – njzk2 Jan 05 '16 at 18:01
  • Yes but the same concept applies. Get the `ClassLoader` and look at the path's it contains. Then check the parent `ClassLoader` for it's path. The code has nothing java app or android specific. (except the main method) – JBirdVegas Jan 05 '16 at 18:17
  • Not really, because all your dependencies are packaged in the same dex file. You'd only get the system classpath, which does not answer the OP's question. – njzk2 Jan 05 '16 at 18:31