안드로이드 개발을 하다보면 Intent를 이용해서 다른 앱의 기능을 호출해서 선택 또는 사용 후의 결과 값을 리턴 받아서 뭔가를 처리하는 작업들을 하게 된다.
이번에는 내부/외부 저장소의 Download 폴더 아래의 PDF 파일 목록을 파일관리자를 통해서 살펴보고, 선택한 PDF파일을 열어서 보여주는 기능을 개발하기 위한 방법을 설명하겠다.
안드로이드 빌드 버전에 따라서 파일을 공유할 수 있는 방법이 다르다.
내가 테스트 했던 기기는 LG X4+ 와 삼성 Galaxy Tab A 였다.
이 두 기기에서 다운로드 폴더를 열어서 PDF파일 목록을 보여주고, 선택한 PDF파일을 열어서 보여주고자 했는데 LG X4+ 기종에서는 문제가 없었으나, Galaxy Tab A에서는 PDF파일이 열리지 않는 문제가 발생했다.
이 문제를 해결하기 위해 구글링 하면 자료를 찾아보다 보니 안드로이드 버전에 따라 생기는 문제 임을 알게 되었다.
Android 8(LG X4+)과 Android 10(Galaxy Tab A)에서 파일 경로를 찾아오는 방법의 차이로 인해 생긴 문제 였다.
먼저 다운로드 폴드의 특정 폴더를 기준으로 파일 관리자를 열기 위한 방법이다.
면저 res폴더 아래에 xml 폴더를 생성하고 filepaths.xml파일을 생성한다.
Storage의 기본 위치를 지정.
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="storage/emulated" path="." />
</paths>
filepaths.xml 파일을 생성한 후에 AndroidManifest.xml 파일을 열어서 provider 를 추가하도록 한다.
<application
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/AppTheme"
android:requestLegacyExternalStorage="true"
android:usesCleartextTraffic="true">
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="패키지명"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
<activity android:name=".BarcodeActivity"></activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
이렇게 설정을 하고 난 뒤에 MainActivity.Java 파일을 열어서 각각의 부분을 아래와 같이 수정한다.
파일관리자를 열어서 파일을 선택할 수 있도록 Intent를 startActivityForResult 로 실행하는 부분이다.
//파일이 위치한 폴더를 지정
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS ).getPath() + "/하위폴드명칭/");
//안드로이드 버전 체크 (Android 8 버전이하와 이상으로 구분)
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_OPENABLE);
Uri uri = Uri.fromFile(file);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
intent.setDataAndType(Uri.fromFile(file), "application/pdf");
try {
startActivityForResult(Intent.createChooser(intent, "File Select"), SELECT_FILE);
} catch (ActivityNotFoundException ex) {
Toast.makeText(this, "Please install a File Manager.", Toast.LENGTH_SHORT).show();
}
} else {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("application/pdf");
startActivityForResult(intent, SELECT_FILE);
}
startActivityForResult를 통해서 선택된 파일을 받아서 PDF파일을 열어주는 부분의 코드는 아래와 같다.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == SELECT_FILE) {
if (resultCode == FILE_SELECT_OK) {
Uri uri = data.getData();
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
String fileUri = data.getData().getPath();
fileUri = fileUri.substring(fileUri.indexOf(":") + 1);
File file = new File(fileUri);
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setAction(android.content.Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setDataAndType(Uri.fromFile(file), "application/pdf");
startActivity(intent);
} else {
String fileName = getFileName(uri);
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath() +
"/하위폴드명칭/" + fileName);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(getBaseContext(), "패키지명", file);
intent.setDataAndType(contentUri, "application/pdf");
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
startActivity(intent);
}
}
}
super.onActivityResult(requestCode, resultCode, data);
}