【问题标题】:Adding ADB to my Java PC application将 ADB 添加到我的 Java PC 应用程序
【发布时间】:2023-12-11 17:08:01
【问题描述】:

我开发了一个 Java 应用程序。应用程序以编程方式连接到 Android 设备以传输一些文件以连接 Android 设备。

在我的应用程序中,我添加了 adb PATH,以便它可以使用它连接到设备。

我想知道是否可以将它打包到应用程序中?还是只是将 adb 复制到应用程序目录中?因为我希望谁曾经下载过这个应用程序,所以不需要下载 adb 或 Android sdk 来让应用程序工作

有可能吗?

【问题讨论】:

    标签: java android adb


    【解决方案1】:

    在做一些研究之后,您可以将一个 exe 打包到一个 jar 文件中,但您必须在每次运行应用程序时提取该 exe。 Following TofuBear's example here 我能够将 adb 封装在一个 jar 文件中。您需要包含 AdbWinApi.dll(或等效的 linux 库)。

    import java.io.BufferedReader;
    import java.io.Closeable;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.URI;
    import java.net.URISyntaxException;
    import java.net.URL;
    import java.security.CodeSource;
    import java.security.ProtectionDomain;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipException;
    import java.util.zip.ZipFile;
    
    public class Sandbox
    {
        public static void main(final String[] args)
            throws URISyntaxException,
                   ZipException,
                   IOException
        {
            final URI uri;
            final URI exe;
    
            uri = getJarURI();
            // Extract the adb application
            exe = getFile(uri, "adb.exe");
            // Extract the AdbWinApi dll file.
            getFile(uri, "AdbWinApi.dll");
            System.out.println(exe);
        }
    
        private static URI getJarURI()
            throws URISyntaxException
        {
            final ProtectionDomain domain;
            final CodeSource       source;
            final URL              url;
            final URI              uri;
    
            domain = Sandbox.class.getProtectionDomain();
            source = domain.getCodeSource();
            url    = source.getLocation();
            uri    = url.toURI();
    
            return (uri);
        }    
    
        private static URI getFile(final URI    where,
                                   final String fileName)
            throws ZipException,
                   IOException
        {
            final File location;
            final URI  fileURI;
    
            location = new File(where);
    
            // not in a JAR, just return the path on disk
            if(location.isDirectory())
            {
                fileURI = URI.create(where.toString() + fileName);
            }
            else
            {
                final ZipFile zipFile;
    
                zipFile = new ZipFile(location);
    
                try
                {
                    fileURI = extract(zipFile, fileName);
                }
                finally
                {
                    zipFile.close();
                }
            }
    
            return (fileURI);
        }
    
        private static URI extract(final ZipFile zipFile,
                               final String  fileName)
            throws IOException
        {
            final File         tempFile;
            final ZipEntry     entry;
            final InputStream  zipStream;
            OutputStream       fileStream;
    
            //tempFile = File.createTempFile(fileName,     Long.toString(System.currentTimeMillis()));
            tempFile = new File(System.getProperty("java.io.tmpdir") + File.separator + fileName);
    
            tempFile.deleteOnExit();
            entry    = zipFile.getEntry(fileName);
    
            if(entry == null)
    
            {
                throw new FileNotFoundException("cannot find file: " + fileName + " in archive: " + zipFile.getName());
            }
    
            zipStream  = zipFile.getInputStream(entry);
            fileStream = null;
    
            try
            {
                final byte[] buf;
                int          i;
    
                fileStream = new FileOutputStream(tempFile);
                buf        = new byte[1024];
                i          = 0;
    
                while((i = zipStream.read(buf)) != -1)
                {
                    fileStream.write(buf, 0, i);
                }
            }
            finally
            {
                close(zipStream);
                close(fileStream);
            }
    
            return (tempFile.toURI());
        }
    
        private static void close(final Closeable stream)
        {
            if(stream != null)
            {
                try
                {
                    stream.close();
                }
                catch(final IOException ex)
                {
                    ex.printStackTrace();
                }
            }
        }
    }
    

    我必须更改 TofuBear 示例中的文件创建,以便不会更改 exe 的文件名。它仍然在临时文件夹中创建,将在退出时被删除。我将原始代码作为注释留下。

    编辑: 似乎我太着迷于它的技术可能性,以至于忘记了法律后果。 stated here by Chris Stratton 一直是 SDK Terms of Service 禁止重新分发 sdk 的任何部分。其中将包括 adb。

    【讨论】:

    • adb 和 SDK 的其他部分使用 Apache 2.0 许可证进行许可。这意味着您可以自己编译并重新分发它。 github.com/android/platform_system_core/blob/master/adb/adb.c
    • 我对此感到困惑。根据 SDK 服务条款,您不得“复制(用于备份目的除外)、修改、改编、重新分发、反编译、反向工程、反汇编或创建 SDK 或 SDK 任何部分的衍生作品”。这直接与 Apache 许可证相矛盾。我能找到的将 sdk 链接到 Apache 许可证的唯一内容是:source.android.com/source/licenses.html,其中“声明大多数 Android 软件都使用 Apache 2.0 获得许可”。它对什么所涵盖的内容进行了一些细分?
    • 消息来源说它们是 Apache 许可证。因此它们可以分发(源,而不是二进制文件)。 Android SDK 是这些源代码的 Google 编译和打包版本——它们可能无法按原样分发。 “大多数 Android 软件都使用 Apache 2.0 许可”中不包括 linux 内核(不是 Apache 的 GPL)和其他专有驱动程序。
    • 为什么说二进制文件不能分发? Apache 许可说:“2. 授予版权许可。根据本许可的条款和条件,每个贡献者特此授予您永久、全球、非排他性、免费、免版税、不可撤销的版权许可,以进行复制,准备衍生作品,公开展示,公开表演,再许可和分发源或对象形式的作品和此类衍生作品。”我不明白为什么不能分发 ADB。
    【解决方案2】:

    使用Java-native chimpchat连接设备应该更容易。

    【讨论】:

      最近更新 更多