第一節 安裝Android Studio 3.5.3
Android Studio 3.5.3下載地址:
Android Studio 3.5.3 December 5, 2019
Windows (32-bit): android-studio-ide-191.6010548-windows32.zip (756.1 MB)
https://redirector.gvt1.com/edgedl/android/studio/ide-zips/3.5.3.0/android-studio-ide-191.6010548-windows32.zip
解壓后運行bin/studio.exe。Windows (64-bit): android-studio-ide-191.6010548-windows.zip (756.6 MB)
https://redirector.gvt1.com/edgedl/android/studio/ide-zips/3.5.3.0/android-studio-ide-191.6010548-windows.zip
解壓后運行bin/studio64.exe。
Android Studio自帶JRE,不需要事先安裝Java。
Android Studio 3.5.3可以在Win7 SP1系統下直接解壓使用。
如果是XP SP3或者64位XP SP2系統的話就必須要先安裝one core api 4.0.1,否則運行不了studio.exe或者studio64.exe。
one core api 4.0.1下載地址:https://github.com/shorthorn-project/One-Core-API-Binaries/releases/download/4.0.1/One-Core-API-Binaries-4.0.1.zip
安裝完成后重啟電腦。
本人用的是64位Windows XP SP2系統,one core api 4.0.1安裝完成后就可以成功運行studio64.exe了。
出現下面的窗口時點Cancel就行。
默認的Android SDK下載路徑C:\Documents and Settings\Administrator\AppData\Local\Android\Sdk是有空格的,必須要改。
例如改成D:\Android\Sdk,路徑中一定不能有空格。
下載過程中如果失敗就多Retry幾次。本人就遇到過幾次域名解析失敗,但過幾分鐘又能下載了。
下載完點擊Finish按鈕,就可以安裝成功了。
第二節 建立普通Java安卓工程并運行
點擊Start a new Android Studio project。
選擇Empty Activity。
Save location要改成一個沒有空格的路徑,默認的路徑C:\Documents and Settings\Administrator\AndroidStudioProjects\MyApplication是有空格的,是不能使用的。
Language要改成Java。
改完后點擊Finish按鈕。
進入工程后會下載gradle-5.4.1-all.zip,但是下載要很長時間。為了避免每次創建新工程都要下載一遍,可以在瀏覽器中下載https://services.gradle.org/distributions/gradle-5.4.1-all.zip,保存到D:\Android文件夾中。
修改工程里面的gradle-wrapper.properties文件(如F:\Projects\AndroidStudioProjects\MyApplication\gradle\wrapper\gradle-wrapper.properties)
把里面的distributionUrl改成file:///D:/Android/gradle-5.4.1-all.zip。
重啟Android Studio,點擊菜單欄里面的File->Sync Project with Gradle Files,就可以立即下載完成了。
點擊解除阻止:
完了之后報了一個錯誤:ERROR: Cause: unable to find valid certification path to requested target
解決辦法是打開Gradle Scripts下面的build.gradle (Project: My Application)文件,將里面的兩處google()修改成maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' },兩處jcenter()修改成maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'},改完后點擊一下上面的Try Again。
adb解除一下阻止:
sync成功:
sync成功后,就可以打開app/res/layout/activity_main.xml,看到可視化設計界面了。
現在我們嘗試生成一下apk安裝包。點擊菜單欄的Build -> Make Project命令。
build失敗,報錯:
AAPT: aapt2.exe E 08-22 19:42:48? 2296? 2152 LoadedArsc.cpp:112] RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data.
aapt2.exe E 08-22 19:42:48? 2296? 2152 ApkAssets.cpp:157] Failed to load 'resources.arsc' in APK 'D:\Android\Sdk\platforms\android-36\android.jar'.
error: failed to load include path D:\Android\Sdk\platforms\android-36\android.jar.
解決辦法是打開Gradle Scripts下面的build.gradle (Module: app)文件。
compileSdkVersion改成28
buildToolsVersion改成"28.0.3"
targetSdkVersion改成28
改完后點擊右上角的Sync Now,等一會后報錯:
ERROR: Failed to install the following Android SDK packages as some licences have not been accepted.
build-tools;28.0.3 Android SDK Build-Tools 28.0.3
platforms;android-28 Android SDK Platform 28
To build this project, accept the SDK license agreements and install the missing components using the Android Studio SDK Manager.
Alternatively, to transfer the license agreements from one workstation to another, see http://d.android.com/r/studio-ui/export-licenses.html
Using Android SDK: D:\Android\Sdk
Install missing SDK package(s)
點擊Install missing SDK package(s),接受一下協議。
點擊Finish后,再點擊一下Build->Make Project菜單,就成功了。
可以在F:\Projects\AndroidStudioProjects\MyApplication\app\build\outputs\apk\debug下成功生成app-debug.apk。
現在我們嘗試一下在命令行中安裝這個apk到手機上運行。
安卓手機USB驅動下載地址:https://www.onlinedown.net/soft/1116709.htm
ADB Interface驅動所在文件夾:1510571328_36999_ysy\adb_interface_usb_driver
這個驅動適用于32位和64位的XP和Win7系統。
首先用USB數據線連接手機和電腦,電腦提示發現新硬件。
開始->運行->cmd打開命令行窗口,運行命令:
D:\Android\Sdk\platform-tools\adb.exe install -t F:\Projects\AndroidStudioProjects\MyApplication\app\build\outputs\apk\debug\app-debug.apk
手機上要允許一下USB Debugging。
進度一直卡住不動,什么都不輸出。這是因為,最新版本的Android SDK Platform-Tools 36.0.0已經不支持XP和Win7系統了,無法正常運行。
去網上下載舊版本的platform-tools:https://dl.google.com/android/repository/platform-tools_r23.1.0-windows.zip。
下載完后先關閉Android Studio,重啟一下電腦。
重啟電腦后先不要打開Android Studio,先把D:\Android\Sdk\platform-tools文件夾刪除掉,把剛剛下載的platform-tools_r23.1.0-windows.zip里面的platform-tools文件夾解壓到D:\Android\Sdk。
再在命令行中運行一下D:\Android\Sdk\platform-tools\adb.exe install -t F:\Projects\AndroidStudioProjects\MyApplication\app\build\outputs\apk\debug\app-debug.apk命令,就成功了。
這個時候再打開Android Studio,點擊Run -> Run 'app'菜單,也能成功安裝apk到手機上運行。
可以看到手機上的logcat:
因為XP系統沒有Powershell,所以Terminal窗格無法使用,要Win7下才能使用。
在SDK Manager里面可以看到,Android SDK Platform-Tools的版本號是23.1。
第三節 建立Native C++安卓工程并運行
先把上一節的工程關了:
然后新建一個Native C++工程:
進去之后還是一樣的先把distributionUrl改成file:///D:/Android/gradle-5.4.1-all.zip,因為從網上下載會失敗。改完后一定要重啟Android Studio,點擊菜單欄里面的File->Sync Project with Gradle Files。
ERROR: Cause: unable to find valid certification path to requested target
一樣的解決方法,打開Gradle Scripts下面的build.gradle (Project: My Application)文件,將里面的兩處google()修改成maven { url 'http://maven.aliyun.com/nexus/content/repositories/google' },兩處jcenter()修改成maven { url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'},改完后點擊一下上面的Try Again。
完了之后會要求我們安裝NDK。
ERROR: Failed to install the following Android SDK packages as some licences have not been accepted.
ndk;29.0.13846066 NDK (Side by side) 29.0.13846066
To build this project, accept the SDK license agreements and install the missing components using the Android Studio SDK Manager.
Alternatively, to transfer the license agreements from one workstation to another, see http://d.android.com/r/studio-ui/export-licenses.html
Using Android SDK: D:\Android\Sdk
NDK 29.0.13846066版本太高,與Android Studio 3.5.3不匹配,一定要安裝低版本的NDK。
在當前工程Sync失敗的情況下,Tools菜單下是沒有SDK Manager命令的,只能從File -> Settings菜單打開。
從File -> Settings菜單打開Settings窗口后,左邊展開Apperance & Behavior -> System Settings -> Android SDK。
右邊打開SDK Tools選項卡,勾選下面的Show Package Details,然后勾選安裝NDK (Side by side) 21.0.6113669版本。
裝完NDK后,點擊File -> Project Structure菜單。
左邊選擇SDK Location,右邊Android NDK location選擇NDK的路徑D:\Android\Sdk\ndk\21.0.6113669。
ERROR: CMake '3.10.2' was not found in PATH or by cmake.dir property.
Install CMake 3.10.2
點擊Install CMake 3.10.2鏈接安裝cmake。
ERROR: CMake '3.10.2' was not found in PATH or by cmake.dir property.
Set cmake.dir in local.properties to D:\Android\Sdk\cmake\3.10.2.4988404
點擊Set cmake.dir in local.properties to D:\Android\Sdk\cmake\3.10.2.4988404鏈接,就可以成功了。
上面的Unable to execute Clang-Tidy: Cannot create property=Diagnostics for JavaBean=com.jetbrains.cidr.lang.daemon.clang.tidy.ClangTidyYamlLoader$YamlData@9aedf45 in 'string', line 2, column 1:? ? MainSourceFile:? ?'F:\Projects\An不用管,不影響工程的編譯和運行。
Build -> Make Project生成apk安裝包。
AAPT: aapt2.exe E 08-22 20:53:53? 2724? 1520 LoadedArsc.cpp:112] RES_TABLE_TYPE_TYPE entry offsets overlap actual entry data.
aapt2.exe E 08-22 20:53:53? 2724? 1520 ApkAssets.cpp:157] Failed to load 'resources.arsc' in APK 'D:\Android\Sdk\platforms\android-36\android.jar'.
error: failed to load include path D:\Android\Sdk\platforms\android-36\android.jar.
修改build.gradle (Module: app)文件。
compileSdkVersion改成28
buildToolsVersion改成"28.0.3"
targetSdkVersion改成28
Sync一下,然后再次Make Project,成功。
Run -> Run 'app',成功。
第四節 下載并使用C++ Oboe音頻庫
Android Studio 3.5.3可以成功導入oboe-1.9.0,但無法成功導入最新版的oboe-1.9.3。
https://github.com/google/oboe/archive/refs/tags/1.9.0.zip(Jun 26, 2024)
https://github.com/google/oboe/archive/refs/tags/1.9.3.zip(Dec 18, 2024)
把oboe-1.9.0.zip下載下來,然后解壓到一個沒有空格的文件夾里面,如D:\Android。
打開app/src/main/cpp/CMakeLists.txt文件,找到末尾的target_link_libraries,在括號里面添加oboe。
然后在下面添加:
set(OBOE_DIR D:\\Android\\oboe-1.9.0)
add_subdirectory(${OBOE_DIR} ./oboe)
include_directories(${OBOE_DIR}/include)
修改完成后,點擊菜單欄里面的Build -> Refresh Linked C++ Projects,然后再Build -> Make Project。
修改代碼。
【com/example/myapplication/MainActivity.java】
package com.example.myapplication;import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;public class MainActivity extends AppCompatActivity {private TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// Example of a call to a native methodtextView = findViewById(R.id.sample_text);}@Overrideprotected void onPause() {super.onPause();stringFromJNI("stop");textView.setText(stringFromJNI("log"));}@Overrideprotected void onResume() {super.onResume();stringFromJNI("start");}/*** A native method that is implemented by the 'native-lib' native library,* which is packaged with this application.*/public native String stringFromJNI(String message);// Used to load the 'native-lib' library on application startup.static {System.loadLibrary("native-lib");}
}
【native-lib.cpp】
#include <jni.h>
#include <string>
#include <oboe/Oboe.h>class OboeSinePlayer: public oboe::AudioStreamDataCallback {
public:OboeSinePlayer() : logCount(0) {}virtual ~OboeSinePlayer() = default;// Call this from Activity onResume()int32_t startAudio() {std::lock_guard<std::mutex> lock(mLock);oboe::AudioStreamBuilder builder;// The builder set methods can be chained for convenience.oboe::Result result = builder.setSharingMode(oboe::SharingMode::Exclusive)->setPerformanceMode(oboe::PerformanceMode::LowLatency)->setChannelCount(kChannelCount)->setSampleRate(kSampleRate)->setSampleRateConversionQuality(oboe::SampleRateConversionQuality::Medium)->setFormat(oboe::AudioFormat::Float)->setDataCallback(this)->openStream(mStream);if (result != oboe::Result::OK) return (int32_t) result;// Typically, start the stream after querying some stream information, as well as some input from the userresult = mStream->requestStart();return (int32_t) result;}// Call this from Activity onPause()void stopAudio() {// Stop, close and delete in case not already closed.std::lock_guard<std::mutex> lock(mLock);if (mStream) {mStream->stop();mStream->close();mStream.reset();}}oboe::DataCallbackResult onAudioReady(oboe::AudioStream *oboeStream, void *audioData, int32_t numFrames) override {println("onAudioReady: numFrames=%d", numFrames);float *floatData = (float *) audioData;for (int i = 0; i < numFrames; ++i) {float sampleValue = kAmplitude * sinf(mPhase);for (int j = 0; j < kChannelCount; j++) {floatData[i * kChannelCount + j] = sampleValue;}mPhase += mPhaseIncrement;if (mPhase >= kTwoPi) mPhase -= kTwoPi;}return oboe::DataCallbackResult::Continue;}std::string getLog() {std::string log = this->log;this->log.clear();return log;}private:std::mutex mLock;std::shared_ptr<oboe::AudioStream> mStream;// Stream paramsstatic int constexpr kChannelCount = 2;static int constexpr kSampleRate = 48000;// Wave params, these could be instance variables in order to modify at runtimestatic float constexpr kAmplitude = 0.5f;static float constexpr kFrequency = 440;static float constexpr kPI = M_PI;static float constexpr kTwoPi = kPI * 2;static double constexpr mPhaseIncrement = kFrequency * kTwoPi / (double) kSampleRate;// Keeps track of where the wave isfloat mPhase = 0.0;std::string log;int logCount;void println(const char *fmt, ...) {char header[30];char buffer[256];va_list list;va_start(list, fmt);vsnprintf(buffer, sizeof(buffer), fmt, list);va_end(list);if (log.empty() || logCount % 100 != 0) {if (!log.empty()) {log += "\n";}snprintf(header, sizeof(header), "[%d] ", logCount);log += header;log += buffer;logCount++;}}
};OboeSinePlayer player;extern "C" JNIEXPORT jstring JNICALL
Java_com_example_myapplication_MainActivity_stringFromJNI(JNIEnv* env,jobject that , jstring message) {std::string hello = "Hello from C++";const char *messageCstr = env->GetStringUTFChars(message, nullptr);if (messageCstr != nullptr) {if (strcmp(messageCstr, "start") == 0) {player.startAudio();} else if (strcmp(messageCstr, "stop") == 0) {player.stopAudio();} else if (strcmp(messageCstr, "log") == 0) {hello = player.getLog();}env->ReleaseStringUTFChars(message, messageCstr);}return env->NewStringUTF(hello.c_str());
}
【layout/activity_main.xml】
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"xmlns:app="http://schemas.android.com/apk/res-auto"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ScrollViewandroid:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/sample_text"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="Hello World!" /></ScrollView></androidx.constraintlayout.widget.ConstraintLayout>
改完代碼,Build -> Make Project,然后Run -> Run 'app',在手機上運行。
APP運行后,在手機上能聽到Oboe發出的聲音,是一段蜂鳴聲。
按HOME鍵(不是返回鍵)關閉APP,停止播放聲音。再重新打開APP,又開始播放聲音了,而且APP上會有日志顯示,每次顯示100條。這個日志是C++代碼里面的println("onAudioReady: numFrames=%d", numFrames);語句打印的。