Android Studio 4 可以构建 API < 9 的项目吗?
Can Android Studio 4 build projects with API < 9?
我希望我的应用支持任何 Android phone api 3 及更高版本。
为什么?因为我不喜欢浪费,而且这些较旧的 phone 完全可以胜任手头的任务。
可悲的是,事实证明,获得有关 api-9 之前的基本 SDK 构建的信息比让 NDK 正常工作要困难得多。
我无法找到一种机制来构建 Android 应用程序 api < 9 使用 developer.android.com 上可用的任何 Android Studio 版本。
但是,可以使用较旧的命令行工具来构建它们。 (我没有研究 api < 9 使用 ActivityCompat 库和 ndk-builds 来调试 JNI 应用程序 - 这些留作 reader 的练习:-)
注意:使用这些技术需要熟悉当今的命令行构建,否则阅读起来毫无意义。
这个任务分为四个:
Android api < 9
的示例项目
https://android.googlesource.com/platform/development/+refs
从 donut-release 到 android-s-beta-4.
应有尽有
每个都有一个 'samples' 子目录,这是一个很好的起点。
Android 构建工具 api < 9 个项目
https://dl.google.com/android/repository/repository-10.xml
列出所有下载及其 digest/checksum,位于:
https://dl.google.com/android/repository/(repo-filename)
您需要查找、下载并安装:
- 平台 sdk 3
- build-tools 17.0.0(最新的包含aapt)
- build-tools 24.0.3(包含 apksigner 的最老版本)
- ndk R11C(最新的支持JNI for apis 3 to 8)
为 api < 9
构建 Android JNI 库
请注意 api < 4 设备似乎更喜欢 link 从设备 OS 而不是 JNI 库中共享符号,因此请避免从您的库和静态 link 任何第三方库(许可证允许。)
示例生成文件:
API = 3
NDK = ~/Android/Sdk/ndk/r11c
CC = $(NDK)/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
SR = $(NDK)/platforms/android-$(API)/arch-arm
INC = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
objs = obj/thing1.o obj/thing2.o ...
libexample.so : $(objs)
$(CC) --sysroot=$(SR) -fPIC -Wall -shared -o libexample.so -O $^
obj/%.o : %.c
$(CC) --sysroot=$(SR) -fPIC -Wall -mthumb -c $< -o $@ $(INC)
如果要构建 openssl,则需要一个额外的配置标志:
--with-rand-seed=devrandom
以及无线程 no-asm。
为 api < 9
构建 Android Java 个应用
遗憾的是,我无法找到一种方法来使用当今的 Android Studio 来构建这些低 api 项目,所以下面是一些令人讨厌的命令行东西来代替它。
您需要查找、下载并安装:
- 平台 sdk 3
- build-tools 17.0.0(最新的包含aapt)
- build-tools 24.0.3(包含 apksigner 的最老版本)
(有关如何获取这些信息,请参见上文。)
项目树
project/
Makefile
app/
build/
src/
main/
AndroidManifest.xml
assets/
jniLibs/
armeabi/
libexample.so
res/
layout/
activity_main.xml
java/
com/
example/
project/
MainActivity.java
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.project">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
>
<uses-sdk android:minSdkVersion="3" />
<activity android:name="com.example.project.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.project.MainActivity"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/outer"
android:orientation="vertical"
>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="run"
/><!--note: no onClick-->
...
MainActivity.java
package com.example.project;
import android.os.Bundle;
import android.app.Activity;
import android.widget.Button;
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle bdl) {
super.onCreate(bdl);
setContentView(R.layout.activity_main);
final Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
...
}
});
}
};
生成文件
API = 3
KEY_PATH = ~/jkeystore
DROID_HOME = ~/Android/Sdk
JAVA_HOME = /usr/lib/jvm/java-8-openjdk-amd64
BLD_TOOLS=17.0.0
APK_SIGNR=24.0.3
PKG_PATH = com/example/project
JVA_ROOT = app/src/main/java
RES_ROOT = app/src/main/res
AST_ROOT = app/src/main/assets
AMF_PNAM = app/src/main/AndroidManifest.xml
LIB_REAL = app/src/main/jniLibs
CLS_ROOT = app/build/intermediates/javac/debug/classes
DEX_PATH = app/build/intermediates/dex/debug/mergeDexDebug
APK_PATH = app/build/outputs/apk/debug
APK_NAME = app-debug
LIB_TEMP = lib
JVA_PRJT = $(JVA_ROOT)/$(PKG_PATH)
CLS_PRJT = $(CLS_ROOT)/$(PKG_PATH)
APK_PNAM = $(APK_PATH)/$(APK_NAME)
DRD_JAR = $(DROID_HOME)/platforms/android-$(API)/android.jar
jopt = -proc:none -Xlint:all -Xlint:-fallthrough -Werror -Xmaxerrs 5
jopt += -implicit:none -target 1.6 -source 1,6 -bootclasspath ~/jre1.6.0_45/lib/rt.jar
# wildcard matches symlinks awa directories. dir filters, sort dedupes.
JVA_DIRS := $(dir $(wildcard $(JVA_PRJT)/*/) )
JVA_DIRS := $(sort $(JVA_DIRS) )
JVA_DIRS += $(JVA_PRJT)/
# all in java tree except R.java (and thus R.class)
temp_jva := $(foreach pth, $(JVA_DIRS), $(wildcard $(pth)*.java) )
JVA_LIST := $(patsubst $(JVA_PRJT)/R.java, , $(temp_jva))
temp_cls := $(patsubst $(JVA_PRJT)/%.java,$(CLS_PRJT)/%.class, $(JVA_LIST))
CLS_LIST := $(patsubst $(JVA_PRJT)/%,$(CLS_PRJT)/%, $(temp_cls))
LIB_LIST := $(shell find $(LIB_REAL) -type f 2> /dev/null)
LIB_TLST := $(patsubst $(LIB_REAL)/%, $(LIB_TEMP)/%, $(LIB_LIST))
AST_LIST := $(shell find $(AST_ROOT) -type f 2> /dev/null)
ifneq ($(strip $(AST_LIST)),)
AST_OPTN = -A $(AST_ROOT)
endif
RES_LIST := $(shell find $(RES_ROOT) -type f)
.DELETE_ON_ERROR:
assembleDebug: $(APK_PNAM).apk
$(APK_PNAM).apk : $(APK_PNAM).nosig.apk $(AMF_PNAM) $(RES_LIST) $(AST_LIST) $(LIB_LIST)
#****************************** SIGN **********************************
$(DROID_HOME)/build-tools/$(APK_SIGNR)/apksigner sign -v --verbose \
--ks $(KEY_PATH) --ks-pass pass:debug_pw --min-sdk-version $(API) \
--out $@ $(APK_PNAM).nosig.apk
$(APK_PNAM).nosig.apk : $(DEX_PATH)/classes.dex $(AMF_PNAM) $(RES_LIST) $(AST_LIST) $(LIB_LIST)
#****************************** PACKAGE *******************************
@-mkdir -p $(APK_PATH)
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/aapt package -v -f -M $(AMF_PNAM) \
-S $(RES_ROOT) $(AST_OPTN) -I $(DRD_JAR) -F $(APK_PNAM).nosig.apk $(DEX_PATH)/
ifneq ($(strip $(LIB_LIST)),)
#****************************** LIBS **********************************
cp -r $(LIB_REAL) $(LIB_TEMP)/
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/aapt add -v $(APK_PNAM).nosig.apk $(LIB_TLST)
@-rm -r $(LIB_TEMP)
endif
$(DEX_PATH)/classes.dex : $(CLS_LIST) $(CLS_PRJT)/R.class
#****************************** LINK **********************************
$(JAVA_HOME)/bin/javac $(jopt) -sourcepath $(JVA_ROOT)/ -cp $(DRD_JAR) \
-d $(CLS_ROOT)/ $(JVA_PRJT)/$(START).java
@-mkdir -p $(DEX_PATH)
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/dx --dex --verbose --output=$@ $(CLS_ROOT)
$(CLS_PRJT)/%.class : $(JVA_PRJT)/%.java $(CLS_PRJT)/R.class
@-mkdir -p $(CLS_PRJT)
$(JAVA_HOME)/bin/javac $(jopt) -sourcepath $(JVA_ROOT)/ -cp $(DRD_JAR) -d $(CLS_ROOT)/ $<
$(CLS_PRJT)/R.class : $(JVA_PRJT)/R.java
#****************************** R.CLASS *******************************
@-mkdir -p $(CLS_PRJT)
$(JAVA_HOME)/bin/javac $(jopt) -sourcepath $(JVA_ROOT)/ -cp $(DRD_JAR) -d $(CLS_ROOT)/ $<
$(JVA_PRJT)/R.java : $(RES_LIST) $(AMF_PNAM)
#****************************** R.JAVA ********************************
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/aapt package -v -f -M $(AMF_PNAM) \
-S $(RES_ROOT) -m -J $(JVA_ROOT) -I $(DRD_JAR)
您可能需要 32 位 zlib:
sudo apt install zlib1g:i386
...并且真的应该得到 java 1.6 用于引导:
https://www.oracle.com/uk/java/technologies/javase-java-archive-javase6-downloads.html
下载jre-6u45-linux-x64.bin(需要注册)
您还需要为 apk 签名配置密钥库:
/usr/lib/jvm/java-8-openjdk-amd64/bin/keytool \
-genkeypair -validity 1000 -dname "CN=some company,O=Android,C=JPN" -keystore ~/jkeystore \
-storepass debug_pw -keypass debug_pw -alias cert -keyalg RSA -v
重要提示:
我应该指出 api < 9 台设备最容易受到移动数据、wifi、网络共享、adb、蓝牙、GSM 等攻击
呸
抱歉,这个 post 太长了,但是当我尝试 post 分段时遇到了 moderator/duplicate 问题...
我希望我的应用支持任何 Android phone api 3 及更高版本。
为什么?因为我不喜欢浪费,而且这些较旧的 phone 完全可以胜任手头的任务。
可悲的是,事实证明,获得有关 api-9 之前的基本 SDK 构建的信息比让 NDK 正常工作要困难得多。
我无法找到一种机制来构建 Android 应用程序 api < 9 使用 developer.android.com 上可用的任何 Android Studio 版本。
但是,可以使用较旧的命令行工具来构建它们。 (我没有研究 api < 9 使用 ActivityCompat 库和 ndk-builds 来调试 JNI 应用程序 - 这些留作 reader 的练习:-)
注意:使用这些技术需要熟悉当今的命令行构建,否则阅读起来毫无意义。
这个任务分为四个:
Android api < 9
的示例项目https://android.googlesource.com/platform/development/+refs
从 donut-release 到 android-s-beta-4.
应有尽有
每个都有一个 'samples' 子目录,这是一个很好的起点。
Android 构建工具 api < 9 个项目
https://dl.google.com/android/repository/repository-10.xml
列出所有下载及其 digest/checksum,位于:
https://dl.google.com/android/repository/(repo-filename)
您需要查找、下载并安装:
- 平台 sdk 3
- build-tools 17.0.0(最新的包含aapt)
- build-tools 24.0.3(包含 apksigner 的最老版本)
- ndk R11C(最新的支持JNI for apis 3 to 8)
为 api < 9
构建 Android JNI 库请注意 api < 4 设备似乎更喜欢 link 从设备 OS 而不是 JNI 库中共享符号,因此请避免从您的库和静态 link 任何第三方库(许可证允许。)
示例生成文件:
API = 3
NDK = ~/Android/Sdk/ndk/r11c
CC = $(NDK)/toolchains/arm-linux-androideabi-4.9/prebuilt/linux-x86_64/bin/arm-linux-androideabi-gcc
SR = $(NDK)/platforms/android-$(API)/arch-arm
INC = -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
objs = obj/thing1.o obj/thing2.o ...
libexample.so : $(objs)
$(CC) --sysroot=$(SR) -fPIC -Wall -shared -o libexample.so -O $^
obj/%.o : %.c
$(CC) --sysroot=$(SR) -fPIC -Wall -mthumb -c $< -o $@ $(INC)
如果要构建 openssl,则需要一个额外的配置标志:
--with-rand-seed=devrandom
以及无线程 no-asm。
为 api < 9
构建 Android Java 个应用遗憾的是,我无法找到一种方法来使用当今的 Android Studio 来构建这些低 api 项目,所以下面是一些令人讨厌的命令行东西来代替它。
您需要查找、下载并安装:
- 平台 sdk 3
- build-tools 17.0.0(最新的包含aapt)
- build-tools 24.0.3(包含 apksigner 的最老版本)
(有关如何获取这些信息,请参见上文。)
项目树
project/
Makefile
app/
build/
src/
main/
AndroidManifest.xml
assets/
jniLibs/
armeabi/
libexample.so
res/
layout/
activity_main.xml
java/
com/
example/
project/
MainActivity.java
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.project">
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
>
<uses-sdk android:minSdkVersion="3" />
<activity android:name="com.example.project.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.project.MainActivity"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/outer"
android:orientation="vertical"
>
<Button
android:id="@+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="run"
/><!--note: no onClick-->
...
MainActivity.java
package com.example.project;
import android.os.Bundle;
import android.app.Activity;
import android.widget.Button;
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle bdl) {
super.onCreate(bdl);
setContentView(R.layout.activity_main);
final Button btn = (Button)findViewById(R.id.btn);
btn.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
...
}
});
}
};
生成文件
API = 3
KEY_PATH = ~/jkeystore
DROID_HOME = ~/Android/Sdk
JAVA_HOME = /usr/lib/jvm/java-8-openjdk-amd64
BLD_TOOLS=17.0.0
APK_SIGNR=24.0.3
PKG_PATH = com/example/project
JVA_ROOT = app/src/main/java
RES_ROOT = app/src/main/res
AST_ROOT = app/src/main/assets
AMF_PNAM = app/src/main/AndroidManifest.xml
LIB_REAL = app/src/main/jniLibs
CLS_ROOT = app/build/intermediates/javac/debug/classes
DEX_PATH = app/build/intermediates/dex/debug/mergeDexDebug
APK_PATH = app/build/outputs/apk/debug
APK_NAME = app-debug
LIB_TEMP = lib
JVA_PRJT = $(JVA_ROOT)/$(PKG_PATH)
CLS_PRJT = $(CLS_ROOT)/$(PKG_PATH)
APK_PNAM = $(APK_PATH)/$(APK_NAME)
DRD_JAR = $(DROID_HOME)/platforms/android-$(API)/android.jar
jopt = -proc:none -Xlint:all -Xlint:-fallthrough -Werror -Xmaxerrs 5
jopt += -implicit:none -target 1.6 -source 1,6 -bootclasspath ~/jre1.6.0_45/lib/rt.jar
# wildcard matches symlinks awa directories. dir filters, sort dedupes.
JVA_DIRS := $(dir $(wildcard $(JVA_PRJT)/*/) )
JVA_DIRS := $(sort $(JVA_DIRS) )
JVA_DIRS += $(JVA_PRJT)/
# all in java tree except R.java (and thus R.class)
temp_jva := $(foreach pth, $(JVA_DIRS), $(wildcard $(pth)*.java) )
JVA_LIST := $(patsubst $(JVA_PRJT)/R.java, , $(temp_jva))
temp_cls := $(patsubst $(JVA_PRJT)/%.java,$(CLS_PRJT)/%.class, $(JVA_LIST))
CLS_LIST := $(patsubst $(JVA_PRJT)/%,$(CLS_PRJT)/%, $(temp_cls))
LIB_LIST := $(shell find $(LIB_REAL) -type f 2> /dev/null)
LIB_TLST := $(patsubst $(LIB_REAL)/%, $(LIB_TEMP)/%, $(LIB_LIST))
AST_LIST := $(shell find $(AST_ROOT) -type f 2> /dev/null)
ifneq ($(strip $(AST_LIST)),)
AST_OPTN = -A $(AST_ROOT)
endif
RES_LIST := $(shell find $(RES_ROOT) -type f)
.DELETE_ON_ERROR:
assembleDebug: $(APK_PNAM).apk
$(APK_PNAM).apk : $(APK_PNAM).nosig.apk $(AMF_PNAM) $(RES_LIST) $(AST_LIST) $(LIB_LIST)
#****************************** SIGN **********************************
$(DROID_HOME)/build-tools/$(APK_SIGNR)/apksigner sign -v --verbose \
--ks $(KEY_PATH) --ks-pass pass:debug_pw --min-sdk-version $(API) \
--out $@ $(APK_PNAM).nosig.apk
$(APK_PNAM).nosig.apk : $(DEX_PATH)/classes.dex $(AMF_PNAM) $(RES_LIST) $(AST_LIST) $(LIB_LIST)
#****************************** PACKAGE *******************************
@-mkdir -p $(APK_PATH)
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/aapt package -v -f -M $(AMF_PNAM) \
-S $(RES_ROOT) $(AST_OPTN) -I $(DRD_JAR) -F $(APK_PNAM).nosig.apk $(DEX_PATH)/
ifneq ($(strip $(LIB_LIST)),)
#****************************** LIBS **********************************
cp -r $(LIB_REAL) $(LIB_TEMP)/
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/aapt add -v $(APK_PNAM).nosig.apk $(LIB_TLST)
@-rm -r $(LIB_TEMP)
endif
$(DEX_PATH)/classes.dex : $(CLS_LIST) $(CLS_PRJT)/R.class
#****************************** LINK **********************************
$(JAVA_HOME)/bin/javac $(jopt) -sourcepath $(JVA_ROOT)/ -cp $(DRD_JAR) \
-d $(CLS_ROOT)/ $(JVA_PRJT)/$(START).java
@-mkdir -p $(DEX_PATH)
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/dx --dex --verbose --output=$@ $(CLS_ROOT)
$(CLS_PRJT)/%.class : $(JVA_PRJT)/%.java $(CLS_PRJT)/R.class
@-mkdir -p $(CLS_PRJT)
$(JAVA_HOME)/bin/javac $(jopt) -sourcepath $(JVA_ROOT)/ -cp $(DRD_JAR) -d $(CLS_ROOT)/ $<
$(CLS_PRJT)/R.class : $(JVA_PRJT)/R.java
#****************************** R.CLASS *******************************
@-mkdir -p $(CLS_PRJT)
$(JAVA_HOME)/bin/javac $(jopt) -sourcepath $(JVA_ROOT)/ -cp $(DRD_JAR) -d $(CLS_ROOT)/ $<
$(JVA_PRJT)/R.java : $(RES_LIST) $(AMF_PNAM)
#****************************** R.JAVA ********************************
$(DROID_HOME)/build-tools/$(BLD_TOOLS)/aapt package -v -f -M $(AMF_PNAM) \
-S $(RES_ROOT) -m -J $(JVA_ROOT) -I $(DRD_JAR)
您可能需要 32 位 zlib:
sudo apt install zlib1g:i386
...并且真的应该得到 java 1.6 用于引导:
https://www.oracle.com/uk/java/technologies/javase-java-archive-javase6-downloads.html
下载jre-6u45-linux-x64.bin(需要注册)
您还需要为 apk 签名配置密钥库:
/usr/lib/jvm/java-8-openjdk-amd64/bin/keytool \
-genkeypair -validity 1000 -dname "CN=some company,O=Android,C=JPN" -keystore ~/jkeystore \
-storepass debug_pw -keypass debug_pw -alias cert -keyalg RSA -v
重要提示:
我应该指出 api < 9 台设备最容易受到移动数据、wifi、网络共享、adb、蓝牙、GSM 等攻击
呸
抱歉,这个 post 太长了,但是当我尝试 post 分段时遇到了 moderator/duplicate 问题...