- 大疆官方開發文檔目前沒有提供中文的api,所以看起來可能會比較麻煩,尤其對于一些專業名詞,基于官方的sdk我們能開發出什么呢?我們基于sdk可以開發出跟DJI go 4一模一樣的功能
- 目前的項目就是先把大疆官方支持的功能全部實現一遍
- 然后在此基礎上實現自己的功能,無論是全自動執行任務,還是遠程控制都沒有問題。我會在后面的篇章教大家如何基于大疆的sdk開發出一個完整的應用。
- 不再做過多的解釋直接上代碼,代碼中有相應的注解
在app下的build.gradle中的dependencies下導包
圖片.png
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 30
defaultConfig {
applicationId ""
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
multiDexEnabled true//這一行加上,否則會運行錯誤
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
packagingOptions {
doNotStrip "*/*/libdjivideo.so"
doNotStrip "*/*/libSDKRelativeJNI.so"
doNotStrip "*/*/libFlyForbid.so"
doNotStrip "*/*/libduml_vision_bokeh.so"
doNotStrip "*/*/libyuv2.so"
doNotStrip "*/*/libGroudStation.so"
doNotStrip "*/*/libFRCorkscrew.so"
doNotStrip "*/*/libUpgradeVerify.so"
doNotStrip "*/*/libFR.so"
doNotStrip "*/*/libDJIFlySafeCore.so"
doNotStrip "*/*/libdjifs_jni.so"
doNotStrip "*/*/libsfjni.so"
doNotStrip "*/*/libDJICommonJNI.so"
doNotStrip "*/*/libDJICSDKCommon.so"
doNotStrip "*/*/libDJIUpgradeCore.so"
doNotStrip "*/*/libDJIUpgradeJNI.so"
doNotStrip "*/*/libDJIWaypointV2Core.so"
doNotStrip "*/*/libAMapSDK_MAP_v6_9_2.so"
doNotStrip "*/*/libDJIMOP.so"
doNotStrip "*/*/libDJISDKLOGJNI.so"
exclude 'META-INF/rxjava.properties'
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation('com.dji:dji-sdk:4.15.1', {
/**
* 如果您的應用程序不需要Mavic 2 Pro和Mavic 2 Zoom的反失真功能,請取消對“庫反失真”的注釋。
* 如果您需要發布數據庫,請取消對“飛行安全數據庫”的注釋,否則我們將在DJISDKManager.getInstance().registerApp時下載它
* 被稱為。
* 兩者都將大大減小APK的大小。
*/
exclude module: 'library-anti-distortion'
exclude module: 'fly-safe-database'
})
compileOnly 'com.dji:dji-sdk-provided:4.15.1'
}
在AndroidManifest.xml文件下添加對應的權限和配置
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="****">
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature
android:name="android.hardware.usb.host"
android:required="false"/>
<uses-feature
android:name="android.hardware.usb.accessory"
android:required="true"/>
<application
android:name=".DroneApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.My_DJ_FlyDemo">
<uses-library android:name="com.android.future.usb.accessory"/>
<uses-library
android:name="org.apache.http.legacy"
android:required="false" />
<!-- personal key -->
<meta-data
android:name="com.dji.sdk.API_KEY"
android:value="請填入您在大疆開發平臺申請的KEY"/>
<activity android:name="dji.sdk.sdkmanager.DJIAoaControllerActivity"
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"/>
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter"/>
</activity>
<service android:name="dji.sdk.sdkmanager.DJIGlobalService"
tools:ignore="Instantiatable" />
<activity android:name=".ui.MainActivity"
android:configChanges="orientation"
android:screenOrientation="portrait"
tools:ignore="LockedOrientationActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
在Application中初始化類庫
public class DroneApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
Helper.install(DroneApplication.this);
}
}
MainActivity的代碼如下
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import com.okq.flydemo.R;
import java.util.ArrayList;
import java.util.List;
import dji.common.error.DJIError;
import dji.common.error.DJISDKError;
import dji.common.realname.AircraftBindingState;
import dji.common.realname.AppActivationState;
import dji.common.useraccount.UserAccountState;
import dji.common.util.CommonCallbacks;
import dji.sdk.base.BaseComponent;
import dji.sdk.base.BaseProduct;
import dji.sdk.realname.AppActivationManager;
import dji.sdk.sdkmanager.DJISDKInitEvent;
import dji.sdk.sdkmanager.DJISDKManager;
import dji.sdk.useraccount.UserAccountManager;
import dji.thirdparty.afinal.core.AsyncTask;
public class MainActivity extends AppCompatActivity {
private static final String[] PERMISSION_LIST = new String[]{
Manifest.permission.VIBRATE, // 程序震動
Manifest.permission.INTERNET, // 訪問互聯網
Manifest.permission.ACCESS_WIFI_STATE, // 獲取 WIFI 狀態和 wifi 接入點信息
Manifest.permission.WAKE_LOCK,//關閉屏幕時后臺進程仍然進行
Manifest.permission.ACCESS_COARSE_LOCATION, // 獲得模糊定位信息
Manifest.permission.ACCESS_NETWORK_STATE, // 獲取網絡狀態信息
Manifest.permission.ACCESS_FINE_LOCATION, // 獲取精準定位信息
Manifest.permission.CHANGE_WIFI_STATE, // 改變wifi連接狀態
Manifest.permission.WRITE_EXTERNAL_STORAGE, // 寫入外部存儲信息
Manifest.permission.BLUETOOTH, // 配對藍牙設備
Manifest.permission.BLUETOOTH_ADMIN, // 配對藍牙設備(不通知用戶)
Manifest.permission.READ_EXTERNAL_STORAGE, // 讀取外部存儲信息
Manifest.permission.READ_PHONE_STATE, // 訪問電話狀態
Manifest.permission.RECORD_AUDIO // 錄音權限
};
//缺失的用戶權限
public static List<String> missingPermission = new ArrayList<>();
private Button btn_login,btn_logout,btn_status_appactivation,btn_status_aircraftbinding;
private TextView tv_status_appactivation,tv_status_aircraftbinding;
//應用程序激活狀態監聽
private AppActivationState.AppActivationStateListener appActivationStateListener;
//無人機綁定狀態監聽
private AircraftBindingState.AircraftBindingStateListener aircraftBindingStateListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//檢查用戶權限
if (!checkPermissions()) {
requestPermissions();
}
if (checkPermissions()) {
//注冊應用程序
registerAppLication();
}
initView();
initListener();
}
private void initListener() {
appActivationStateListener = new AppActivationState.AppActivationStateListener() {
@Override
public void onUpdate(AppActivationState appActivationState) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_status_appactivation.setText("當前應用激活狀態:"+appActivationState.name());
}
});
}
};
aircraftBindingStateListener = new AircraftBindingState.AircraftBindingStateListener() {
@Override
public void onUpdate(AircraftBindingState aircraftBindingState) {
runOnUiThread(new Runnable() {
@Override
public void run() {
tv_status_aircraftbinding.setText("當前無人機綁定狀態:"+aircraftBindingState.name());
}
});
}
};
//添加應用程序激活監聽
AppActivationManager.getInstance().addAppActivationStateListener(appActivationStateListener);
//添加無人機綁定監聽
AppActivationManager.getInstance().addAircraftBindingStateListener(aircraftBindingStateListener);
}
@Override
protected void onDestroy() {
super.onDestroy();
//移除應用程序激活監聽
AppActivationManager.getInstance().removeAppActivationStateListener(appActivationStateListener);
//移除無人機綁定監聽
AppActivationManager.getInstance().removeAircraftBindingStateListener(aircraftBindingStateListener);
}
private void initView() {
tv_status_appactivation = (TextView) findViewById(R.id.tv_status_appactivation);
tv_status_aircraftbinding = (TextView) findViewById(R.id.tv_status_aircraftbinding);
//登錄dji賬號
btn_login = (Button)findViewById(R.id.btn_login);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UserAccountManager.getInstance().logIntoDJIUserAccount(MainActivity.this, new CommonCallbacks.CompletionCallbackWith<UserAccountState>() {
@Override
public void onSuccess(UserAccountState userAccountState) {
ShowToas("登錄成功");
}
@Override
public void onFailure(DJIError djiError) {
ShowToas("登錄失?。?+djiError.getDescription());
}
});
}
});
//退出賬號
btn_logout = (Button)findViewById(R.id.btn_logout);
btn_logout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
UserAccountManager.getInstance().logoutOfDJIUserAccount(new CommonCallbacks.CompletionCallback() {
@Override
public void onResult(DJIError djiError) {
if (djiError == null){
ShowToas("退出成功");
}else {
ShowToas("退出失?。?+djiError.getDescription());
}
}
});
}
});
//獲取應用激活狀態
btn_status_appactivation = (Button)findViewById(R.id.btn_status_appactivation);
btn_status_appactivation.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AppActivationManager appActivationManager = DJISDKManager.getInstance().getAppActivationManager();
AppActivationState appActivationState = appActivationManager.getAppActivationState();
ShowToas("激活狀態:"+appActivationState);
if (!(""+appActivationState).equals("ACTIVATED")){
Intent launchIntentForPackage = getPackageManager().getLaunchIntentForPackage("dji.go.v4");
if (launchIntentForPackage != null){
startActivity(launchIntentForPackage);
}else {
ShowToas("未安裝 DJI Go");
}
}
}
});
//獲取無人機綁定狀態
btn_status_aircraftbinding = (Button)findViewById(R.id.btn_status_aircraftbinding);
btn_status_aircraftbinding.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AppActivationManager appActivationManager = DJISDKManager.getInstance().getAppActivationManager();
AircraftBindingState aircraftBindingState = appActivationManager.getAircraftBindingState();
ShowToas("綁定狀態:"+aircraftBindingState);
if (!(""+aircraftBindingState).equals("BOUND")){
Intent launchIntentForPackage = getPackageManager().getLaunchIntentForPackage("dji.go.v4");
if (launchIntentForPackage != null){
startActivity(launchIntentForPackage);
}else {
ShowToas("未安裝 DJI Go 4");
}
}
}
});
}
//注冊程序
private void registerAppLication() {
AsyncTask.execute(new Runnable() {
@Override
public void run() {
DJISDKManager.getInstance().registerApp(MainActivity.this.getApplicationContext(), new DJISDKManager.SDKManagerCallback() {
@Override
public void onRegister(DJIError djiError) {//注冊應用程序回調方法
if (djiError == DJISDKError.REGISTRATION_SUCCESS) {
ShowToas("onRegister--->應用注冊成功:" + djiError.getDescription());
DJISDKManager.getInstance().enableBridgeModeWithBridgeAppIP("192.168.1.189");
} else {
ShowToas("onRegister--->應用注冊失敗:" + djiError.getDescription());
}
}
@Override
public void onProductDisconnect() {//無人機失去連接回調
ShowToas("onProductDisconnect--->設備斷開連接");
}
@Override
public void onProductConnect(BaseProduct baseProduct) {//無人機連接回調
if (baseProduct.getModel() == null){
return;
}
ShowToas("onProductConnect--->設備連接"+baseProduct.getModel().getDisplayName());
}
@Override
public void onProductChanged(BaseProduct baseProduct) {//無人機連接變化回調
if (baseProduct == null){
return;
}
ShowToas("onProductChanged--->設備連接"+baseProduct.getModel().getDisplayName());
}
//無人機組件 變化變化回調
@Override
public void onComponentChange(BaseProduct.ComponentKey componentKey, BaseComponent baseComponent, BaseComponent baseComponent1) {
ShowToas("onComponentChange--->"+String.format("組件變化 鍵:%s,舊組件:%s,新組件:%s",componentKey,baseComponent,baseComponent1));
}
@Override
public void onInitProcess(DJISDKInitEvent djisdkInitEvent, int i) {//初始化進程回調
ShowToas("onInitProcess--->"+djisdkInitEvent.getInitializationState().toString() + "進度:" + i + "%");
}
@Override
public void onDatabaseDownloadProgress(long l, long l1) {//限飛數據庫下載進度回調
// ShowToas("onDatabaseDownloadProgress--->已下載: "+l+"字節,總共:"+l1+"字節");
Log.i("TAG", "onDatabaseDownloadProgress--->已下載: "+l+"字節,總共:"+l1+"字節");
}
});
}
});
}
private void ShowToas(String msg){
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
}
});
}
public boolean checkPermissions() {
//判斷應用程序編輯的SDK版本是否大于22
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
for (String string : PERMISSION_LIST) {
if (ContextCompat.checkSelfPermission(MainActivity.this, string) != PackageManager.PERMISSION_GRANTED) {
//沒有賦予的權限添加到集合中
missingPermission.add(string);
}
}
return missingPermission.isEmpty();
} else {
return false;
}
}
public void requestPermissions() {
//申請所有沒有被賦予的權限
ActivityCompat.requestPermissions(MainActivity.this, missingPermission.toArray(new String[missingPermission.size()]), 1009);
}
}
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".ui.MainActivity">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="應用激活與無人機綁定"/>
<TextView
android:id="@+id/tv_status_appactivation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:text="當前應用程序激活狀態:UNKNOWN"
android:gravity="center"/>
<TextView
android:id="@+id/tv_status_aircraftbinding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="35dp"
android:gravity="center"
android:text="當前無人機綁定狀態:UNKNOWN"/>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="70dp"
android:layout_marginRight="70dp"
android:layout_marginTop="35dp"
android:text="登錄DJI賬號"/>
<Button
android:id="@+id/btn_logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="70dp"
android:layout_marginRight="70dp"
android:layout_marginTop="35dp"
android:text="退出DJI賬號"/>
<Button
android:id="@+id/btn_status_appactivation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="70dp"
android:layout_marginRight="70dp"
android:layout_marginTop="35dp"
android:text="獲取應用激活狀態"/>
<Button
android:id="@+id/btn_status_aircraftbinding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="70dp"
android:layout_marginRight="70dp"
android:layout_marginTop="35dp"
android:text="獲取無人機綁定狀態"/>
</LinearLayout>
-
至此就能獲取對應的設備狀態和賬號登錄等狀態,我使用的御2無人機
圖片.png
DJI Go 4下載地址(https://www.dji.com/cn/downloads/djiapp/dji-go-4)
- 參考資料《大疆無人機二次開發教程》