공유 파일 요청

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

이 과정에서는 클라이언트 앱이 서버 앱에서 파일을 요청하고 파일의 콘텐츠 URI를 가져와서 콘텐츠 URI를 사용하여 파일을 엽니다.

파일 요청 전송

서버 앱에서 파일을 요청하기 위해 클라이언트 앱은 startActivityForResult 다음과 같은 작업이 포함된 Intent ACTION_PICK 및 클라이언트 앱의 MIME 유형 처리할 수 있습니다.

예를 들어, 다음 코드 스니펫은 Intent를 서버 앱에 연결하여 파일 공유에서 설명한 Activity는 다음과 같습니다.

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)
        ...
    }
    ...
}

자바

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를 IntentIntent는 클라이언트에 전달됩니다. 앱이 onActivityResult()의 재정의에서 사용됩니다. 한 번 클라이언트 앱이 파일의 콘텐츠 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
        ...
    }
}

자바

    /*
     * 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 객체를 가져와 파일을 읽는 데 사용할 수 있습니다.

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