【问题标题】:Hello world using the Android SDK alone (no IDE)单独使用 Android SDK(无 IDE)的 Hello world
【发布时间】:2015-05-24 13:43:43
【问题描述】:

我的目标是:

  1. 在一个简单的程序上测试基本的开发工具
  2. 将程序扩展为有用的应用程序

与 IDE 相比,我更喜欢使用小型、独立的工具。与声明式 (XML) 相比,我更喜欢以过程式或命令式(简单的旧 Java)编写代码。

我安装了独立的 Android SDK as instructed。我拥有最少的其他工具(文本编辑器、命令 shell 和 JDK)。但我能找到的唯一启动说明与 Android Studio、Eclipse 或其他 IDE 相关。我跟不上他们。

如何使用文本编辑器编写 Java 程序以在 Android 设备上显示“Hello world”?如何使用 SDK 模拟器对其进行测试?请给我指示。

【问题讨论】:

    标签: android android-build


    【解决方案1】:

    首先,真的不要考虑使用模拟器。除非你只是想接受不必要的折磨。对于不想要 IDE 包袱的人来说,仿真器要差 100 倍。获取设备将是关于这一点的建议。

    您将无法放弃 XML。我理解并感谢我有类似的冲动。然而,我最终爱上了它。大量使用样式。我建议使用 Android Studio。它为代码和界面构建器标记提供了一个很棒的 lint 工具。

    即使您只想从编辑器中编写代码,您也可能希望使用 Android Studio 来制作您的项目存根。这很擅长。如果您不知道这一点,在文档中,有一种创建项目的命令行方式(不使用 AS):它记录在 here

    【讨论】:

    • 您对 xml 文件所做的大部分操作(例如创建布局)都可以在代码中完成,尽管效率可能较低。例外情况是必须的 AndroidManifest.xml。
    • 我知道这一点。在大多数情况下这样做的逻辑非常有限,并且无法随时调整布局。
    • 谢谢,我错过了those instructions 还是一样,我觉得依赖13个文件自动生成源代码与“hello world”的精神背道而驰。那就是工具自己说“你好世界”。相反,我想使用工具(最基本的工具)说“hello world”,并亲身体验至少需要什么。跨度>
    • 明白。那么您对这种方法感到满意吗?或者没有?您是说即使使用命令行工具,因为它生成 14 个文件,它并没有真正实现硬件的目的?
    • 这就是我的意思。 android create project 不是最小的,因为它写入了太多文件。此外,它不是基本工具。它编写了一个 XML 构建脚本,要求我安装 Ant,然后让 Ant 代替我使用这些工具。 (最后还是有帮助。我破译了脚本并找到了答案。我会尽快发布。)
    【解决方案2】:

    这些是最终对我有用的说明。我通过解构 Rob 的答案所基于的 Google 的 Ant 脚本得到了它们。


    以下内容来自 Stack Overflow 文档中的“没有 IDE 的 Android 编程” (archived here);版权所有 2017 geekygeniusMichael AllancascalDoron BeharmnoronhaAndroidMechanic;领有牌照 在 CC BY-SA 3.0 下。完整堆栈溢出的存档 文档内容可以在 archive.org 上找到,其中 示例按其主题 ID:85 进行索引,例如:9496。

    这是一个极简的 Hello World 示例,仅使用最基本的 Android 工具。

    要求和假设

    本示例假设 Linux。您可能需要针对自己的平台调整语法。

    设置 Android SDK

    解压 SDK 版本后:

    1. 使用 SDK 管理器安装其他包。 不要按照捆绑的 Readme.txt 中的说明使用android update sdk --no-ui; 它会下载大约 30 GB 的不必要文件。 而是使用交互式 SDK 管理器android sdk 获得推荐的最少软件包。

    2. 将以下 JDK 和 SDK 目录附加到您的执行路径中。 这是可选的,但下面的说明假定它。

      • JDK/bin
      • SDK/平台工具
      • SDK/工具
      • SDK/build-tools/LATEST (在步骤 1 中安装)
    3. 创建一个 Android 虚拟设备。 使用交互式 AVD 管理器 (android avd)。 您可能需要摆弄一下并寻求建议; on-site instructions 并不总是有帮助。

      (您也可以使用自己的设备)

    4. 运行设备:

      emulator -avd DEVICE
      
    5. 如果设备屏幕似乎被锁定,则滑动解锁。

      在编写应用程序时让它运行。

    编写应用程序

    1. 切换到一个空的工作目录。

    2. 制作源文件:

      mkdir --parents src/dom/domain
      touch src/dom/domain/SayingHello.java
      

      内容:

      package dom.domain;
      import android.widget.TextView;
      
      public final class SayingHello extends android.app.Activity
      {
          protected @Override void onCreate( final android.os.Bundle activityState )
          {
              super.onCreate( activityState );
              final TextView textV = new TextView( SayingHello.this );
              textV.setText( "Hello world" );
              setContentView( textV );
          }
      }
      
    3. 添加清单:

      touch AndroidManifest.xml
      

      内容:

      <?xml version='1.0'?>
      <manifest xmlns:a='http://schemas.android.com/apk/res/android'
       package='dom.domain' a:versionCode='0' a:versionName='0'>
          <application a:label='Saying hello'>
              <activity a:name='dom.domain.SayingHello'>
                   <intent-filter>
                      <category a:name='android.intent.category.LAUNCHER'/>
                      <action a:name='android.intent.action.MAIN'/>
                      </intent-filter>
                  </activity>
              </application>
          </manifest>
      
    4. 为声明的资源创建一个子目录:

      mkdir res
      

      暂时留空。

    构建代码

    1. 为资源声明生成源。 在此处替换您的 SDK 的正确路径, 以及要构建的已安装 API(例如“android-23”):

      aapt package -f \
        -I SDK/platforms/android-API/android.jar \
        -J src -m \
        -M AndroidManifest.xml -S res -v
      

      资源声明(下面进一步描述)实际上是可选的。 同时,如果 res/ 仍然为空,上述调用什么也不做。

    2. 将源代码编译成Java字节码(.java → .class):

      javac \
        -bootclasspath SDK/platforms/android-API/android.jar \
        -classpath src -source 1.7 -target 1.7 \
        src/dom/domain/*.java
      
    3. 将字节码从 Java 翻译成 Android(.class → .dex):

      首先使用 Jill (.class → .jayce):

      java -jar SDK/build-tools/LATEST/jill.jar \
        --output classes.jayce src
      

      然后是杰克(.jayce → .dex):

      java -jar SDK/build-tools/LATEST/jack.jar \
        --import classes.jayce --output-dex .
      

      Android 字节码曾经被称为“Dalvik 可执行代码”,因此被称为“dex”。

      如果您愿意,您可以将步骤 11 和 12 替换为对 Jack 的一次调用; 它可以直接从 Java 源代码(.java → .dex)编译。 但是使用javac 编译有一些优势。 它是一种知名度更高、文档更完善且适用范围更广的工具。

    4. 打包资源文件,包括清单:

      aapt package -f \
        -F app.apkPart \
        -I SDK/platforms/android-API/android.jar \
        -M AndroidManifest.xml -S res -v
      

      这会导致部分 APK 文件(Android 应用程序包)。

    5. 使用ApkBuilder 工具制作完整的 APK:

      java -classpath SDK/tools/lib/sdklib.jar \
        com.android.sdklib.build.ApkBuilderMain \
        app.apkUnalign \
        -d -f classes.dex -v -z app.apkPart
      

      它警告说,“此工具已弃用。有关详细信息,请参阅 --help。” 如果--help 失败并返回ArrayIndexOutOfBoundsException, 然后不传递任何参数:

      java -classpath SDK/tools/lib/sdklib.jar \
        com.android.sdklib.build.ApkBuilderMain
      

      它说明 CLI (ApkBuilderMain) 已弃用 支持直接调用 Java API (ApkBuilder)。 (如果您知道如何从命令行执行此操作,请更新此示例。)

    6. 优化APK的数据对齐方式(recommended practice):

      zipalign -f -v 4 app.apkUnalign app.apk
      

    安装和运行

    1. 将应用安装到 Android 设备:

      adb install -r app.apk
      
    2. 启动应用程序:

      adb shell am start -n dom.domain/.SayingHello
      

      它应该运行并打个招呼。

    就是这样。这就是使用基本的 Android 工具打招呼所需要的。

    声明资源

    此部分是可选的。 简单的“hello world”应用程序不需要资源声明。 如果您的应用也不需要它们, 那么您可以通过省略第 10 步来简化构建, 并从第 13 步中删除对 res/ 目录的引用。

    否则,这里有一个关于如何声明资源的简短示例, 以及如何引用它。

    1. 添加资源文件:

      mkdir res/values
      touch res/values/values.xml
      

      内容:

      <?xml version='1.0'?>
      <resources>
          <string name='appLabel'>Saying hello</string>
      </resources>
      
    2. 从 XML 清单中引用资源。 这是一种声明式的引用风格:

      <!-- <application a:label='Saying hello'> -->
           <application a:label='@string/appLabel'>
      
    3. 从 Java 源引用相同的资源。 这是一个必要的参考:

      // v.setText( "Hello world" );
         v.setText( "This app is called "
           + getResources().getString( R.string.appLabel ));
      
    4. 通过重新构建、重新安装测试上述修改 并重新运行应用程序(步骤 10-17)。

      它应该重新启动并说,“这个应用程序叫做 Saying hello”。

    卸载应用程序

    adb uninstall dom.domain
    

    另见

    【讨论】:

    • 我建议进行编辑以启动应用程序,如图所示 here - adb shell monkey -p com.domain.PackageName 1
    • @Doron 也许你错过了:启动命令位于“安装和运行”部分。它应该如图所示工作。
    • @MichaelAllan 这是一个适用于 Windows 的软件包:github.com/josephernest/helloworldandroidapp_withoutIDE。还有一个小错误(现在无法编译:stackoverflow.com/questions/47200409/…),有什么想法吗?
    • 一个 20 步的过程,只为一个“Hello World!”应用。哎呀!
    • @Calmarius 我很想看看你是否有一个更短的过程,拜托。
    【解决方案3】:

    非常有用的帖子。我使用您非常好的说明制作了一个简单的亮度设置器。只是希望我能单独为 Jack 找出参数。能够将所有内容放在一个目录中,除了需要在 res\drawable-hdpi 中找到的图标。

    javac -bootclasspath c:\android\SDK/platforms/android-19/android.jar -classpath . *.java
    java -jar c:\android\SDK/build-tools/24.0.1/jill.jar --output classes.jayce .
    java -jar c:\android\SDK/build-tools/24.0.1/jack.jar --import classes.jayce --output-dex .
    aapt package -f -F app.apkPart -I c:\android\SDK/platforms/android-19/android.jar -M AndroidManifest.xml -S res -v
    java -classpath c:\android\SDK/tools/lib/sdklib.jar com.android.sdklib.build.ApkBuilderMain app.apkUnalign -d -f classes.dex -v -z app.apkPart
    zipalign -f -v 4 app.apkUnalign brite.apk
    
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="dom.domain"
        android:versionCode="1"
        android:versionName="1.0" >
        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="19" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS"></uses-permission>
        <application
            android:allowBackup="true"
            android:icon="@drawable/slkimage"
            android:label="brite" >
            <activity
                android:name="dom.domain.MainActivity"
                android:label="brite" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    【讨论】:

      【解决方案4】:

      由于 Jack 和 Jill 已经过时,我不得不修改一些命令。

      安装了/a中的sdk,ndk(这个hello world没有用到ndk),系统中的jdk,/usr/bin中的android-tools-adb等(这个包含adb和fastboot和电话定义,以便它可以检测到它们)。

      我将此添加到.bashrc

      export JAVA_HOME=/usr/lib64/java
      export ANDROID_HOME=/a
      export ANDROID_PLATFORM=$ANDROID_HOME/platforms/android-23
      export ANDROID_BUILD_TOOLS=$ANDROID_HOME/build-tools/28.0.0-rc1
      export ANDROID_NDK=$ANDROID_HOME/ndk
      export ANDROID_TOOLS=$ANDROID_HOME/tools # sdk tools
      PATH=$PATH:$JAVA_HOME/bin:$ANDROID_HOME:$ANDROID_BUILD_TOOLS:$ANDROID_NDK:$ANDROID_TOOLS:$ANDROID_TOOLS/bin:$ANDROID_PLATFORM
      

      这是我修改后的命令:

      sdkmanager --list
      sdkmanager "platforms;android-23"
      sdkmanager platform-tools
      
      mkdir /a/prj
      cd /a/prj
      mkdir --parents src/dom/domain
      vi src/dom/domain/SayingHello.java
      
      package dom.domain;
      import android.widget.TextView;
      
      public final class SayingHello extends android.app.Activity
      {
          protected @Override void onCreate( final android.os.Bundle activityState )
          {
              super.onCreate( activityState );
              final TextView textV = new TextView( SayingHello.this );
              textV.setText( "Hello world" );
              setContentView( textV );
          }
      }
      
      vi AndroidManifest.xml
      <?xml version='1.0'?>
      <manifest xmlns:a='http://schemas.android.com/apk/res/android'
       package='dom.domain' a:versionCode='0' a:versionName='0'>
          <application a:label='Saying hello'>
              <activity a:name='dom.domain.SayingHello'>
                   <intent-filter>
                      <category a:name='android.intent.category.LAUNCHER'/>
                      <action a:name='android.intent.action.MAIN'/>
                      </intent-filter>
                  </activity>
              </application>
          </manifest>
      

      如果选择改用res/目录,修改源代码和AndroidManifest.xml如下图:

      # this section is OPTIONAL , the hello world can run without any res
      mkdir res/values -p
      vi res/values/values.xml
      <?xml version='1.0'?>
      <resources>
          <string name='appLabel'>Saying hello</string>
      </resources>
      # Reference the resource from the AndroidManifest.xml manifest.
      vi AndroidManifest.xml
      <!-- <application a:label='Saying hello'> --> <!-- edit this -->
           <application a:label='@string/appLabel'>
      
      vi src/dom/domain/SayingHello.java
      // v.setText( "Hello world" );    // edit this
         v.setText( "This app is called "
           + getResources().getString( R.string.appLabel ));
      # end OPTIONAL section
      

      我还创建了一个构建脚本,buildprj

      #!/bin/bash
      
      #Generate the source for the resource declarations. 
      aapt package -f \
        -I $ANDROID_PLATFORM/android.jar \
        -J src -m \
        -M AndroidManifest.xml -S res -v
      
      #Compile the source code to Java bytecode (.java ニ .class)
      javac \
        -bootclasspath $ANDROID_PLATFORM/android.jar \
        -classpath src -source 1.7 -target 1.7 \
        src/dom/domain/*.java
      
      #Translate the bytecode from Java to Android (.class ニ .dex)
      dx --dex --output="classes.dex" src
      
      #Package up the resource files, including the manifest
      aapt package -f -F app.apkPart -I $ANDROID_PLATFORM/android.jar \
      -M AndroidManifest.xml -S res -v
      
      #Make the full APK using the ApkBuilder tool:
      CLASSPATH=$ANDROID_TOOLS/lib/* java  \
      com.android.sdklib.build.ApkBuilderMain app.apkUnalign \
      -d -f classes.dex -v -z app.apkPart
      
      #Optimize the data alignment of the APK (recommended practice https://developer.android.com/studio/command-line/zipalign.html ):
      zipalign -f -v 4 app.apkUnalign app.apk
      
      adb install -r app.apk
      adb shell am start -n dom.domain/.SayingHello
      
      echo "To uninstall the app: adb uninstall dom.domain"
      # cleanup
      rm app.apkPart app.apkUnalign classes.dex
      find . -name "*.class" -exec rm {} +
      find . -name "R.java" -exec rm {} +
      

      要运行构建脚本,只需调用它:

      ./buildprj # run the build script
      

      在此过程中我遇到了一些陷阱:

      java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
        com.android.sdklib.build.ApkBuilderMain \
        app.apkUnalign \
        -d -f classes.dex -v -z app.apkPart 
      it gave an error that didn't say "sdklib.jar doesn't exist/is not found" 
      Error: Could not find or load main class com.android.sdklib.build.ApkBuilderMain
      ... :( 
      
      cd /a/tools/lib/
      ln -s sdklib-25.3.1.jar sdklib.jar
      
      java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
        com.android.sdklib.build.ApkBuilderMain \
        app.apkUnalign \
        -d -f classes.dex -v -z app.apkPart 
      Exception in thread "main" java.lang.NoClassDefFoundError: com/android/prefs/AndroidLocatio
      
      java -classpath $ANDROID_TOOLS/lib/sdklib.jar \
        com.android.sdklib.build.ApkBuilderMain \
        app.apkUnalign \
        -d -f classes.dex -v -z app.apkPart --help
      THIS TOOL IS DEPRECATED. See --help for more information.
      Unknown argument: --help
      

      哇...

      无论如何,事实证明它只是在解释不推荐使用 CLI (ApkBuilderMain) 以支持直接调用 Java API (ApkBuilder)。如果您知道如何从命令行执行此操作,请更新此示例。更新:实际上从命令行似乎不可能做到这一点,所以警告有点奇怪......

      "If --help fails with an ArrayIndexOutOfBoundsException, then instead pass no arguments:
      
      java -classpath SDK/tools/lib/sdklib.jar \
        com.android.sdklib.build.ApkBuilderMain
      " all right...
      

      【讨论】:

      • 感谢更新dx 版本,我也没有找到Jill 或Jack。
      【解决方案5】:

      dx 命令现在不可用,Apk Builder 需要配置密钥。这是我的设置...

      安装

      您需要软件开发工具包 (SDK), Java 开发工具包 (JDK) 和一个密钥文件。

      1. 要在没有 IDE 的情况下使用 SDK,请下载 Command line tools here
      2. 解压缩Command line tools(例如unzip commandlinetools-linux.zip)。
      3. 将目录cmdline-tools 移动到一个方便的位置并将其重命名为SDK(例如mv cmdline-tools ~/.android/SDK)。
      4. 转到SDK/bin 并运行(见注1)
      ./sdkmanager --sdk_root=../ --list
      ./sdkmanager --sdk_root=../ "platforms;android-31"
      ./sdkmanager --sdk_root=../ platform-tools
      ./sdkmanager --sdk_root=../ "build-tools;31.0.0"
      
      1. 下载JDK 11版here(>11不适用于android java虚拟机)。
      2. 在一个方便的目录中解压 JDK 并将其重命名为 JDK(例如unzip openjdk-11.zip ; mv jdk-11 ~/.android/JDK)。
      3. 转到JDK/bin 并使用./keytool -genkey -keystore ~/.keystore -keyalg RSA 创建密钥。
      4. 制作一个脚本来编译您的应用程序。例如(见注 2)
      #!/bin/bash
      
      # Script to compile a android application source.
      # The argument of the scrit is the directory of the source code (e.g. `ac hello_world/`),
      # this directory may be have the file `AndroidManifest.xml`, the `res` directory
      # and subdirectories containing the java source files.
      
      cd "$1"
      
      # ###
      # seting up the ambient variables
      # ###
      export JAVA_HOME="$HOME/.android/JDK"
      export ANDROID_HOME="$HOME/.android/SDK"
      
      export ANDROID_PLATFORM="$ANDROID_HOME/platforms/android-31"
      export ANDROID_BUILD_TOOLS="$ANDROID_HOME/build-tools/31.0.0"
      export ANDROID_TOOLS="$ANDROID_HOME/tools"
      
      export PATH=$JAVA_HOME/bin:$ANDROID_BUILD_TOOLS:$ANDROID_TOOLS:$PATH
      
      # ###
      # Compile the code
      # ###
      
      # Compile the source code to Java bytecode (.java to .class)
      javac -cp $ANDROID_PLATFORM/android.jar $(find . -name "*.java")
      
      # Translate the bytecode from Java to Android (.class to .dex)
      d8 --lib $ANDROID_PLATFORM/android.jar $(find . -name "*.class")
      
      # Package up the resource files, including the manifest
      aapt package -f \
      -F app.apkPart \
      -I $ANDROID_PLATFORM/android.jar \
      -M AndroidManifest.xml \
      -S res/
      
      # Make the full APK using the `ApkBuilder` tool
      CLASSPATH=$ANDROID_TOOLS/lib/* java \
      com.android.sdklib.build.ApkBuilderMain app.apkUnalign \
      -u -f classes.dex -z app.apkPart
      
      # Optimize the data alignment of the APK
      zipalign -f 4 app.apkUnalign app_aligned.apk
      
      # Signer the APK
      apksigner sign --ks ~/.keystore --out app.apk app_aligned.apk
      
      # ###
      # Remove generated files
      # ###
      rm app.apkUnalign
      rm app_aligned.apk
      rm app.apkPart
      rm classes.dex
      find . -name "*.class" -exec rm {} +
      
      exit 0
      
      1. 将脚本放入 bin 目录中(例如 ~/bin/ac/bin/acac 是脚本名称)并使其可执行(例如 chmod 755 ~/ac)。

      注意事项:

      1. platforms;android-31build-tools;31.0.0 说“将工具下载到 android 的 API 31”但您可以下载另一个版本,请参阅带有 ./sdkmanager --sdk_root=../ --list | grep "platforms;android"./sdkmanager --sdk_root=../ --list | grep "build-tools;" 的 disponible 版本。
      2. 此脚本假设您将 SDK 和 JDK 放在 ~/.android/SDK~/.android/JDK 中,并假设您下载了适用于 android API 31 的工具。

      阅读更多:

      编码

      您基本上需要两个文件,AndroidManifest.xmlMainActivity.java。 最终,您需要资源,用于更高级的程序,位于名为 res 的目录中,在此示例中 res 目录为空。

      AndroidManifest.xml的内容如下。

      <?xml version='1.0'?>
      
      <manifest xmlns:android='http://schemas.android.com/apk/res/android'
         package='com.your_company.app'
         android:versionCode='0'>
      
         <application
            android:label='App name'>
      
            <activity
               android:name='com.your_company.app.MainActivity'>
               <intent-filter>
                  <category android:name='android.intent.category.LAUNCHER'/>
                  <action android:name='android.intent.action.MAIN'/>
               </intent-filter>
            </activity>
      
         </application>
      
      </manifest>
      

      MainActivity.java的内容如下。

      package com.your_company.app;
      
      import android.app.Activity;
      import android.widget.TextView;
      import android.os.Bundle;
      
      public final class MainActivity extends Activity {
         @Override
         protected void onCreate(final Bundle activityState){
            super.onCreate(activityState);
            final TextView textV = new TextView(MainActivity.this);
            textV.setText("Hello World");
            setContentView( textV );
         }
      }
      

      通常将文件MainActivity.java 放在名为src/com/your_company/app/ 的目录中。文件树如下所示。

      hello_world/
       |
       |--- AndroidManifest.xml
       |--- res/
       |--- src/
             |--- com/
                   |--- your_company/
                         |--- app/
                               |--- MainActivity.java
      

      假设您有一个命令通知源目录,并且该命令为您的源调用编译器(参见安装部分第 8 项)并且命令名称为ac,在终端中打开目录hello_world并输入

      ac ./
      

      现在将文件app.apk复制到您的手机并安装它。

      【讨论】:

        猜你喜欢
        • 2012-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-09
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多