Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีแชร์ข้อมูลแอปไปยังแอปพลิเคชันอื่นใน Android (ACTION_SEND)

ภาพรวม

การแชร์ข้อมูล (Sharing) ใน Android ใช้ **Implicit Intent** ด้วย Action Intent.ACTION_SEND ร่วมกับ Intent.createChooser() เพื่อแสดง Dialog ให้ผู้ใช้เลือกแอปปลายทาง (Email, Messenger, Social, Bluetooth, ฯลฯ)

ขั้นตอนการสร้าง

1. Layout (res/layout/activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="24dp">

    <TextView
        android:id="@+id/tvContent"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="https://www.example.com/article/awesome-tips"
        android:textSize="18sp"
        android:autoLink="web"
        android:layout_marginBottom="24dp" />

    <Button
        android:id="@+id/btnShareText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="แชร์ข้อความนี้" />

    <Button
        android:id="@+id/btnShareImage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:text="แชร์รูปภาพ (ตัวอย่าง)" />

</LinearLayout>

2. MainActivity.java

package com.example.myapplication;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.FileProvider;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class MainActivity extends AppCompatActivity {

    private TextView tvContent;
    private Button btnShareText, btnShareImage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvContent = findViewById(R.id.tvContent);
        btnShareText = findViewById(R.id.btnShareText);
        btnShareImage = findViewById(R.id.btnShareImage);

        // แชร์ข้อความธรรมดา (Text/URL)
        btnShareText.setOnClickListener(v -> shareText());

        // แชร์รูปภาพ (ต้องมีไฟล์จริง)
        btnShareImage.setOnClickListener(v -> shareImage());
    }

    private void shareText() {
        String text = tvContent.getText().toString().trim();
        if (text.isEmpty()) {
            Toast.makeText(this, "ไม่มีข้อความให้แชร์", Toast.LENGTH_SHORT).show();
            return;
        }

        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("text/plain");
        intent.putExtra(Intent.EXTRA_TEXT, text);
        intent.putExtra(Intent.EXTRA_SUBJECT, "แชร์จากแอปของฉัน"); // Optional: สำหรับ Email

        // สร้าง Chooser Dialog
        Intent chooser = Intent.createChooser(intent, "แชร์ผ่าน...");
        
        // Verify มีแอปรับโจทย์หรือไม่
        if (intent.resolveActivity(getPackageManager()) != null) {
            startActivity(chooser);
        } else {
            Toast.makeText(this, "ไม่มีแอปที่รองรับการแชร์ข้อความ", Toast.LENGTH_SHORT).show();
        }
    }

    private void shareImage() {
        // ตัวอย่าง: คัดลอกรูปจาก Assets → Cache → แชร์
        // ใน Production ใช้ไฟล์จริงจาก Storage/ContentProvider
        try {
            File cacheFile = new File(getCacheDir(), "shared_image.png");
            copyFromAssetsToCache("sample_image.png", cacheFile);

            // ใช้ FileProvider เพื่อความปลอดภัย (API 24+ ต้องใช้)
            Uri contentUri = FileProvider.getUriForFile(
                this,
                getPackageName() + ".fileprovider",
                cacheFile
            );

            Intent intent = new Intent(Intent.ACTION_SEND);
            intent.setType("image/png");
            intent.putExtra(Intent.EXTRA_STREAM, contentUri);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); // สำคัญ!

            Intent chooser = Intent.createChooser(intent, "แชร์รูปภาพผ่าน...");
            if (intent.resolveActivity(getPackageManager()) != null) {
                startActivity(chooser);
            } else {
                Toast.makeText(this, "ไม่มีแอปที่รองรับการแชร์รูปภาพ", Toast.LENGTH_SHORT).show();
            }
        } catch (IOException e) {
            Toast.makeText(this, "เตรียมรูปภาพล้มเหลว: " + e.getMessage(), Toast.LENGTH_SHORT).show();
        }
    }

    private void copyFromAssetsToCache(String assetName, File dest) throws IOException {
        try (InputStream is = getAssets().open(assetName);
             FileOutputStream fos = new FileOutputStream(dest)) {
            byte[] buffer = new byte[4096];
            int len;
            while ((len = is.read(buffer)) > 0) {
                fos.write(buffer, 0, len);
            }
        }
    }
}

3. AndroidManifest.xml (สำหรับ FileProvider)

<manifest ...>
    <application ...>
        <provider
            android:name="androidx.core.content.FileProvider"
            android:authorities="${applicationId}.fileprovider"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
</manifest>

4. res/xml/file_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="https://schemas.android.com/apk/res/android">
    <cache-path name="shared_images" path="." />
</paths>

MIME Types ที่ใช้บ่อย

ประเภทMIME TypeExtra Key
ข้อความ/URLtext/plainEXTRA_TEXT
HTMLtext/htmlEXTRA_TEXT, EXTRA_HTML_TEXT
อีเมล (RFC822)message/rfc822EXTRA_EMAIL, EXTRA_SUBJECT, EXTRA_TEXT
รูปภาพimage/* (jpeg, png, gif)EXTRA_STREAM (Uri)
วิดีโอvideo/*EXTRA_STREAM
ไฟล์ทั่วไปapplication/*EXTRA_STREAM
หลายไฟล์Action: ACTION_SEND_MULTIPLEEXTRA_STREAM (ArrayList<Uri>)

แชร์ไฟล์หลายไฟล์ (Multiple Files)

ArrayList uris = new ArrayList<>();
uris.add(contentUri1);
uris.add(contentUri2);

Intent intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
intent.setType("image/*");
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(Intent.createChooser(intent, "แชร์หลายรูป"));

Direct Share Targets (Android 10+ / API 29+)

เพื่อให้แอปปรากฏใน **Direct Share** (แถบแชร์โดยตรงบน Sharesheet) ให้เพิ่ม `ShortcutManager` และ `ShareTarget` ใน Manifest (XML) - รายละเอียดดูในเอกสาร Android Developers: Receiving simple data from other apps

Best Practices

  • ใช้ Intent.createChooser() ทุกครั้ง (User control, ไม่บังคับแอปเดียว)
  • เช็ค resolveActivity() ก่อน startActivity ป้องกัน Crash
  • ใช้ **FileProvider** สำหรับไฟล์ (API 24+ ห้ามใช้ file:// URI)
  • เพิ่ม FLAG_GRANT_READ_URI_PERMISSION ให้ Uri
  • ตั้งค่า MIME Type ให้เฉพาะเจาะจง (image/png แทน image/*) เพื่อกรองแอปที่เกี่ยวข้อง
  • สำหรับข้อความยาว ใช้ EXTRA_HTML_TEXT ร่วมกับ EXTRA_TEXT

สรุป

แชร์ข้อมูลใน Android = Intent.ACTION_SEND + MIME Type + Extra Data + Intent.createChooser() + FileProvider (สำหรับไฟล์) รองรับ Text, HTML, Email, Image, Video, Multiple files ได้ครบครัน