공유 파일 요청

앱이 다른 앱에서 공유한 파일에 액세스하려고 할 때 요청 앱 (클라이언트)은 일반적으로 파일을 공유하는 앱 (서버)에 요청을 보냅니다. 대부분의 경우 요청은 공유할 수 있는 파일을 표시하는 서버 앱에서 Activity를 시작합니다. 사용자가 파일을 선택하면 서버 앱이 파일의 콘텐츠 URI를 클라이언트 앱에 반환합니다.

이 과정에서는 클라이언트 앱이 서버 앱에 파일을 요청하고, 서버 앱에서 파일의 콘텐츠 URI를 수신하여 콘텐츠 URI를 사용하여 파일을 여는 방법을 보여줍니다.

파일 요청 전송

서버 앱에서 파일을 요청하기 위해 클라이언트 앱은 ACTION_PICK와 같은 작업과 클라이언트 앱이 처리할 수 있는 MIME 유형이 포함된 Intent를 사용하여 startActivityForResult를 호출합니다.

예를 들어 다음 코드 스니펫은 파일 공유에 설명된 Activity를 시작하기 위해 서버 앱에 Intent를 전송하는 방법을 보여줍니다.

Kotlin

class MainActivity : Activity() {
    private lateinit var requestFileIntent: Intent
    private lateinit var inputPFD: ParcelFileDescriptor
    ...
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        requestFileIntent = Intent(Intent.ACTION_PICK).apply {
            type = "image/jpg"
        }
        ...
    }
    ...
    private fun requestFile() {
        /**
         * When the user requests a file, send an Intent to the
         * server app.
         * files.
         */
        startActivityForResult(requestFileIntent, 0)
        ...
    }
    ...
}

Java

public class MainActivity extends Activity {
    private Intent requestFileIntent;
    private ParcelFileDescriptor inputPFD;
    ...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        requestFileIntent = new Intent(Intent.ACTION_PICK);
        requestFileIntent.setType("image/jpg");
        ...
    }
    ...
    protected void requestFile() {
        /**
         * When the user requests a file, send an Intent to the
         * server app.
         * files.
         */
            startActivityForResult(requestFileIntent, 0);
        ...
    }
    ...
}

요청한 파일에 액세스

서버 앱은 파일의 콘텐츠 URI를 Intent의 클라이언트 앱으로 다시 보냅니다. 이 IntentonActivityResult()의 재정의에서 클라이언트 앱에 전달됩니다. 클라이언트 앱이 파일의 콘텐츠 URI를 갖게 되면 FileDescriptor를 가져와 파일에 액세스할 수 있습니다.

콘텐츠 URI가 클라이언트 앱이 수신하는 유일한 데이터이므로 이 프로세스에서는 파일 보안이 유지됩니다. 이 URI는 디렉터리 경로를 포함하지 않으므로 클라이언트 앱은 서버 앱의 다른 어떤 파일도 찾아서 열 수 없습니다. 클라이언트 앱만 서버 앱에서 부여한 권한에 액세스할 수 있습니다. 권한은 일시적이므로 클라이언트 앱의 작업 스택이 완료되면 서버 앱 외부에서 파일에 더 이상 액세스할 수 없습니다.

다음 스니펫에서는 클라이언트 앱이 서버 앱에서 보낸 Intent를 처리하는 방법과 클라이언트 앱이 콘텐츠 URI를 사용하여 FileDescriptor를 가져오는 방법을 보여줍니다.

Kotlin

/*
 * When the Activity of the app that hosts files sets a result and calls
 * finish(), this method is invoked. The returned Intent contains the
 * content URI of a selected file. The result code indicates if the
 * selection worked or not.
 */
public override fun onActivityResult(requestCode: Int, resultCode: Int, returnIntent: Intent) {
    // If the selection didn't work
    if (resultCode != Activity.RESULT_OK) {
        // Exit without doing anything else
        return
    }
    // Get the file's content URI from the incoming Intent
    returnIntent.data?.also { returnUri ->
        /*
         * Try to open the file for "read" access using the
         * returned URI. If the file isn't found, write to the
         * error log and return.
         */
        inputPFD = try {
            /*
             * Get the content resolver instance for this context, and use it
             * to get a ParcelFileDescriptor for the file.
             */
            contentResolver.openFileDescriptor(returnUri, "r")
        } catch (e: FileNotFoundException) {
            e.printStackTrace()
            Log.e("MainActivity", "File not found.")
            return
        }

        // Get a regular file descriptor for the file
        val fd = inputPFD.fileDescriptor
        ...
    }
}

Java

    /*
     * When the Activity of the app that hosts files sets a result and calls
     * finish(), this method is invoked. The returned Intent contains the
     * content URI of a selected file. The result code indicates if the
     * selection worked or not.
     */
    @Override
    public void onActivityResult(int requestCode, int resultCode,
            Intent returnIntent) {
        // If the selection didn't work
        if (resultCode != RESULT_OK) {
            // Exit without doing anything else
            return;
        } else {
            // Get the file's content URI from the incoming Intent
            Uri returnUri = returnIntent.getData();
            /*
             * Try to open the file for "read" access using the
             * returned URI. If the file isn't found, write to the
             * error log and return.
             */
            try {
                /*
                 * Get the content resolver instance for this context, and use it
                 * to get a ParcelFileDescriptor for the file.
                 */
                inputPFD = getContentResolver().openFileDescriptor(returnUri, "r");
            } catch (FileNotFoundException e) {
                e.printStackTrace();
                Log.e("MainActivity", "File not found.");
                return;
            }
            // Get a regular file descriptor for the file
            FileDescriptor fd = inputPFD.getFileDescriptor();
            ...
        }
    }

openFileDescriptor() 메서드는 파일의 ParcelFileDescriptor를 반환합니다. 클라이언트 앱은 이 객체에서 FileDescriptor 객체를 가져오고 이 객체를 사용하여 파일을 읽을 수 있습니다.

추가 관련 정보는 다음을 참조하세요.