這兩天弄了一下android相簿的相關功能。還是花了挺長時間的,這裡總結一下,避免以後再踩坑。同時也在這篇文章裡面補齊一些android開發的基礎支援
開啟Android相簿並選一個圖片進行顯示
分為幾個步驟:
-
QtCreator新建Android工程
本例使用的是arm64-v8 Android開發套件。
-
構建工程並在構建目錄中找到AndroidManifest.xml
建立的Android工程build之後都會在android-build根目錄下生成一個AndroidManifest.xml檔案。這個檔案是android開發很重要個的一個檔案,是應用清單。專案中引用的java包、app的橫屏和豎屏、app的是否全屏等等很多功能都是在裡面設定的。下面有一些詳細的參考文章:
-
在工程中新增AndroidManifest.xml和java檔案。
java檔案是自己建立的用來寫一些java程式碼呼叫android原生功能的相當於c++中的一個類的檔案。
java檔案可以從網上找一個來參考著寫。等會我會附上gitee的地址供大家參考。
放出java的程式碼簡單看一下吧:
public class OpenAndroidAlbum extends QtActivity { public static native void fileSelected(String fileName); static final int REQUEST_OPEN_IMAGE = 1; public String lastCameraFileUri; static final int REQUEST_CAPTURE_IMAGE = 2; private static OpenAndroidAlbum m_instance; public OpenAndroidAlbum() { m_instance = this; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override protected void onDestroy() { super.onDestroy(); } static void openAnImage() { m_instance.dispatchOpenGallery(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { System.out.println("===dispatchOpenGallery1==="); if (resultCode == RESULT_OK) { if(requestCode == REQUEST_OPEN_IMAGE) { String filePath = getRealPathFromURI(getApplicationContext(), data.getData()); fileSelected(filePath); } } else { // fileSelected(":("); } super.onActivityResult(requestCode, resultCode, data); } private void dispatchOpenGallery() { Intent intent = new Intent(Intent.ACTION_PICK); intent.setType("image/*"); startActivityForResult(intent, REQUEST_OPEN_IMAGE); } public String getRealPathFromURI(Context context, Uri contentUri) { Cursor cursor = null; try { String[] proj = { MediaStore.Images.Media.DATA }; cursor = context.getContentResolver().query(contentUri, proj, null, null, null); int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); cursor.moveToFirst(); System.out.println(column_index); return cursor.getString(column_index); } finally { if (cursor != null) { cursor.close(); } } } }
-
fileSelected這個靜態函式是我們在c++程式碼中定義的。java和c++的混合程式設計是通過JNI來實現的,
#ifdef Q_OS_ANDROID #ifdef __cplusplus extern "C" { #endif JNIEXPORT void JNICALL Java_org_qtproject_example_OpenAndroidAlbum_OpenAndroidAlbum_fileSelected(JNIEnv */*env*/, jobject /*obj*/, jstring results) { selectedFileName = QAndroidJniObject(results).toString(); qDebug() << "fileName = " << selectedFileName; } #ifdef __cplusplus } #endif #endif
名字看起來很長Java是固定頭部,org_qtproject_example_OpenAndroidAlbum這個是java包名,OpenAndroidAlbum是類名,最後fileSelected這個才是函式名。需要注意的是由於jni函式名對映成java函式名的時候是依靠“”來間隔包、類、方法的,如果你的函式中有“”字元的話,jni必須能夠區分函式名中的“_”是字元還是分隔符,所以在函式名前面需要加1用於區分。
由於JNI的函式是c函式,所以要加上
extern "C"
。這樣定義好之後的函式就可以在java中直接呼叫了,還是很方便的。 -
openAnImage是我們定義開啟圖片按鈕的響應函式
java中定義的函式在c++中呼叫的方法是通過Qt的QAndroidJniObject類的一個靜態方法實現的:
QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/OpenAndroidAlbum/OpenAndroidAlbum", "openAnImage", "()V");
第一個引數是類名其實也是包名,是在java檔案中通過
package org.qtproject.example.OpenAndroidAlbum;
定義的。
-
dispatchOpenGallery這個方法用來呼叫相簿
通過Intent物件和startActivityForResult實現呼叫。這裡有一個坑,
Intent intent = new Intent(Intent.ACTION_PICK);
建立物件的時候ACTION_PICK這個列舉要用對,4.4以後的版本好像要用這個,我也是之前怎麼都打不開相簿,改了這個列舉之後就可以了。 -
onActivityResult在相簿中選中一張圖片之後會呼叫這個回撥
很自然就會想到我們在c++中定義的fileSelected函式要在這個地方呼叫了。把路徑轉換成java的String型別,呼叫
fileSelected(filePath)
就可以在Qt程式碼中處理圖片路徑了。
-
在Qt程式碼中呼叫java的開啟相簿的方法,同時利用JNI定義一個c++的處理方法
這個我們在上一條中也提到了。這裡提一下編碼中容易出錯的地方
QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/OpenAndroidAlbum/OpenAndroidAlbum", "openAnImage", "()V");
第一個字串代表java包,相當於一個c++的類。如果遇到編譯過程中遇到“找不到類"的類似錯誤提示檢查一下第一個字串,最後是以OpenAndroidAlbum.java包的字首結尾的,切記!!!
-
AndroidManifest.xml要做相應的修改
上面也提到了,這個檔案是清單列表可以用來指定要呼叫j的ava包
<manifest package="org.qtproject.example.OpenAndroidAlbum" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto"> <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="28"/>
把package=這個包名的屬性做對應的修改。
-
完成了上述5點之後還要修改軟體的許可權,獲取允許開啟相簿的許可權之後才能正常的開啟相簿圖片
gitee地址:https://gitee.com/guiguzicom/Demo/tree/master/OpenAndroidAlbum