Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 融雲如何實現文件發送(高級進階)

融雲如何實現文件發送(高級進階)

編輯:關於Android編程

干貨來啦~!

想在聊天中發 小視頻gif 動圖發紅包? 發 自定義表情? 沒有問題!在融雲統統都可以實現! 以上不管是 小視頻 還是 gif 還是 紅包 或者是 自定義表情 歸根結底都是數據的傳輸 文件的傳輸. 後綴無非是 .png .gif .mp4 .amr 等 所以我們只要掌握了文件發送上面的所有需求都能根據文件消息衍生實現。 那我們就來趕緊切入正題看看文件消息的實現和文件消息的收發吧 Let’s Go!


先來看看效果:

pic


接下來這邊會把是實現原理 和 實現代碼給大家分享

實現原理:

消息需要自定義消息類型 使用融雲的消息收發通道 UI展示 需要使用到 融雲消息模板 可以自定義UI展示樣式 利用 後台存儲 或者 雲存儲(此處示例七牛) 上傳的文件 再給予這個文件一個 可下載的公網路徑(例:http://xxx & https://xxx) 發消息其實就是把本地文件上傳(你需要有個 upLoadFile 類似的方法), 以及上傳進度提示 收到消息 用戶點擊消息 此時就是獲取消息體中包含的 retomeUrl 然後去下載 (你需要有個 downLoadFile 類似的方法) 下載下來以後對文件然後根據自身 App 邏輯需求自行處理

實現代碼:

FileMessage 此類是 文件消息 實體類 繼承自融雲 MessageContent FileMessageProvider 此類是 文件消息模板 負責消息在會話界面 UI 的展示 SendFileProvider 此類是發送文件消息的入口
以上是三個最主要的邏輯代碼類, 先大概說下用途. 還有一些細節代碼.後續會跟上代碼再做詳細分享

FileMessage

package io.rong.message;

import android.annotation.SuppressLint;
import android.net.Uri;
import android.os.Parcel;
import android.text.TextUtils;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;

import io.rong.common.ParcelUtils;
import io.rong.imlib.MessageTag;
import io.rong.imlib.model.MessageContent;
import io.rong.imlib.model.UserInfo;

/**
 * Created by Bob on 15/12/24.
 */
@SuppressLint("ParcelCreator")
@MessageTag(value = "RC:FileMsg", flag = MessageTag.ISCOUNTED | MessageTag.ISPERSISTED, messageHandler = FileMessageHandler.class)
public class FileMessage extends MessageContent {
    private Uri mThumUri;
    private Uri mLocalUri;
    private Uri mRemoteUri;
    private boolean mUpLoadExp = false;
    private String mBase64;
    boolean mIsFull;
    protected String extra;

    /**
     * 獲取消息附加信息
     *
     * @return 附加信息
     */
    public String getExtra() {
        return extra;
    }

    /**
     * 設置消息附加信息
     *
     * @param extra 附加信息
     */
    public void setExtra(String extra) {
        this.extra = extra;
    }

    public FileMessage(byte[] data) {
        String jsonStr = new String(data);

        try {
            JSONObject jsonObj = new JSONObject(jsonStr);

            if (jsonObj.has("fileUri")) {
                String uri = jsonObj.optString("fileUri");
                if(!TextUtils.isEmpty(uri))
                    setRemoteUri(Uri.parse(uri));
                if (getRemoteUri() != null && getRemoteUri().getScheme() != null && getRemoteUri().getScheme().equals("file")) {
                    setLocalUri(getRemoteUri());
                }
            }

            if (jsonObj.has("content")) {
                setBase64(jsonObj.optString("content"));
            }
            if (jsonObj.has("extra")) {
                setExtra(jsonObj.optString("extra"));
            }
            if (jsonObj.has("exp")) {
                setUpLoadExp(true);
            }
            if (jsonObj.has("isFull")) {
                setIsFull(jsonObj.optBoolean("isFull"));
            }
            if (jsonObj.has("user")) {
                setUserInfo(parseJsonToUserInfo(jsonObj.getJSONObject("user")));
            }
        } catch (JSONException e) {
            Log.e("JSONException", e.getMessage());
        }
    }

    public FileMessage() {

    }

    private FileMessage(Uri thumbUri, Uri localUri) {
        mThumUri = thumbUri;
        mLocalUri = localUri;
    }

    private FileMessage(Uri thumbUri, Uri localUri, boolean original) {
        mThumUri = thumbUri;
        mLocalUri = localUri;
        mIsFull = original;
    }

    /**
     * 生成FileMessage對象。
     *
        */
    public static FileMessage obtain(Uri thumUri, Uri localUri) {
        return new FileMessage(thumUri, localUri);
    }

    /**
     * 生成FileMessage對象。
     *
     */
    public static FileMessage obtain(Uri thumUri, Uri localUri, boolean isFull) {
        return new FileMessage(thumUri, localUri, isFull);
    }

    /**
     * 生成FileMessage對象。
     *
     * @return ImageMessage對象實例。
     */
    public static FileMessage obtain() {
        return new FileMessage();
    }

    /**
     * 獲取縮略圖Uri。
     *
     * @return 縮略圖Uri(收消息情況下此為內部Uri,需要通過ResourceManager.getInstance().getFile(new Resource(Uri))方式才能獲取到真實地址)。
     */
    public Uri getThumUri() {
        return mThumUri;
    }

    /**
        *
     * @return true / false
     */
    public boolean isFull() {
        return mIsFull;
    }

    /**
     * 設置發送原圖標志位。
     *
         */
    public void setIsFull(boolean isFull) {
        this.mIsFull = isFull;
    }

    /**
     * 設置縮略圖Uri。
     *
     * @param thumUri 縮略圖地址
     */
    public void setThumUri(Uri thumUri) {
        this.mThumUri = thumUri;
    }

    /**
     * 獲取本地圖片地址(file:///)。
     *
     * @return 本地圖片地址(file:///)。
     */
    public Uri getLocalUri() {
        return mLocalUri;
    }

    /**
     * 設置本地圖片地址(file:///)。
     *
     * @param localUri 本地圖片地址(file:///).
     */
    public void setLocalUri(Uri localUri) {
        this.mLocalUri = localUri;
    }

    /**
     * 獲取網絡圖片地址(http://)。
     *
     * @return 網絡圖片地址(http://)。
     */
    public Uri getRemoteUri() {
        return mRemoteUri;
    }

    /**
     * 設置網絡圖片地址(http://)。
     *
     * @param remoteUri 網絡圖片地址(http://)。
     */
    public void setRemoteUri(Uri remoteUri) {
        this.mRemoteUri = remoteUri;
    }

    /**
     * 設置需要傳遞的Base64數據
     *
     * @param base64 base64數據。
     */
    public void setBase64(String base64) {
        mBase64 = base64;
    }

    /**
     * 獲取需要傳遞的Base64數據。
     *
     * @return base64數據。
     */
    public String getBase64() {
        return mBase64;
    }

    /**
     * 是否上傳失敗。
     *
     * @return 是否上傳失敗。
     */
    public boolean isUpLoadExp() {
        return mUpLoadExp;
    }

    /**
     * 設置是否上傳失敗。
     *
     * @param upLoadExp 上傳是否失敗。
     */
    public void setUpLoadExp(boolean upLoadExp) {
        this.mUpLoadExp = upLoadExp;
    }

    @Override
    public byte[] encode() {
        JSONObject jsonObj = new JSONObject();

        try {
            if (!TextUtils.isEmpty(mBase64)) {
                jsonObj.put("content", mBase64);
            } else {
                Log.d("ImageMessage", "base64 is null");
            }

            if (mRemoteUri != null) {
                jsonObj.put("fileUri", mRemoteUri.toString());
            } else if (getLocalUri() != null) {
                jsonObj.put("fileUri", getLocalUri().toString());
            }

            if (mUpLoadExp) {
                jsonObj.put("exp", true);
            }
            jsonObj.put("isFull", mIsFull);
            if (!TextUtils.isEmpty(getExtra()))
                jsonObj.put("extra", getExtra());
            if (getJSONUserInfo() != null)
                jsonObj.putOpt("user", getJSONUserInfo());
        } catch (JSONException e) {
            Log.e("JSONException", e.getMessage());
        }
        mBase64 = null;
        return jsonObj.toString().getBytes();
    }

    /**
     * 描述了包含在 Parcelable 對象排列信息中的特殊對象的類型。
     *
     * @return 一個標志位,表明Parcelable對象特殊對象類型集合的排列。
     */
    @Override
    public int describeContents() {
        return 0;
    }

    /**
     * 構造函數。
     *
     * @param in 初始化傳入的 Parcel。
     */
    public FileMessage(Parcel in) {
        setExtra(ParcelUtils.readFromParcel(in));
        mLocalUri = ParcelUtils.readFromParcel(in, Uri.class);
        mRemoteUri = ParcelUtils.readFromParcel(in, Uri.class);
        mThumUri = ParcelUtils.readFromParcel(in, Uri.class);
        setUserInfo(ParcelUtils.readFromParcel(in, UserInfo.class));
        mIsFull = ParcelUtils.readIntFromParcel(in) == 1;
    }

    /**
     * 將類的數據寫入外部提供的 Parcel 中。
     *
     * @param dest  對象被寫入的 Parcel。
     * @param flags 對象如何被寫入的附加標志,可能是 0 或 PARCELABLE_WRITE_RETURN_VALUE。
     */
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        ParcelUtils.writeToParcel(dest, getExtra());
        ParcelUtils.writeToParcel(dest, mLocalUri);
        ParcelUtils.writeToParcel(dest, mRemoteUri);
        ParcelUtils.writeToParcel(dest, mThumUri);
        ParcelUtils.writeToParcel(dest, getUserInfo());
        ParcelUtils.writeToParcel(dest, mIsFull ? 1 : 0);
    }

    /**
     * 讀取接口,目的是要從Parcel中構造一個實現了Parcelable的類的實例處理。
     */
    public static final Creator CREATOR = new Creator() {

        @Override
        public FileMessage createFromParcel(Parcel source) {
            return new FileMessage(source);
        }

        @Override
        public FileMessage[] newArray(int size) {
            return new FileMessage[size];
        }
    };
}

自定義消息類裡面主要做了消息的持久序列化 和 消息包含的內容和成員, 例如上傳文件我肯定需要知道文件的本地路徑,例如發送紅包消息我們需要知道紅包的金額


FileMessageProvider

package io.rong.app.message.provider;

import android.content.Context;
import android.text.Spannable;
import android.text.SpannableString;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.sea_monster.resource.Resource;

import io.rong.app.R;
import io.rong.imkit.RongContext;
import io.rong.imkit.model.ProviderTag;
import io.rong.imkit.model.UIMessage;
import io.rong.imkit.widget.AsyncImageView;
import io.rong.imkit.widget.provider.IContainerItemProvider;
import io.rong.imlib.model.Message;
import io.rong.message.FileMessage;

/**
 * Created by Bob on 15/12/24.
 */
@ProviderTag(messageContent = FileMessage.class, showPortrait = true, showProgress = true, centerInHorizontal = false)
public class FileMessageProvider extends IContainerItemProvider.MessageProvider {

    /**
     * 初始化View
     */
    @Override
    public View newView(Context context, ViewGroup group) {
        View view = LayoutInflater.from(context).inflate(R.layout.de_item_file_message, group,false);

        ViewHolder holder = new ViewHolder();

        holder.message = (TextView) view.findViewById(R.id.rc_msg);
        holder.img = (AsyncImageView) view.findViewById(R.id.rc_img);

        view.setTag(holder);
        return view;
    }

    @Override
    public void bindView(View v, int position, FileMessage content, UIMessage message) {
        final ViewHolder holder = (ViewHolder) v.getTag();

        if (message.getMessageDirection() == Message.MessageDirection.SEND) {
            v.setBackgroundResource(io.rong.imkit.R.drawable.rc_ic_bubble_no_right);
        } else {
            v.setBackgroundResource(io.rong.imkit.R.drawable.rc_ic_bubble_no_left);
        }

        holder.img.setResource(content.getThumUri() == null ? null : new Resource(content.getThumUri()));

        int progress = message.getProgress();

        Message.SentStatus status = message.getSentStatus();

        if (status.equals(Message.SentStatus.SENDING) && progress < 100) {

            if (progress == 0)
                holder.message.setText(RongContext.getInstance().getResources().getString(io.rong.imkit.R.string.rc_waiting));
            else
                holder.message.setText(progress + "%");

            holder.message.setVisibility(View.VISIBLE);
        } else {
            holder.message.setVisibility(View.GONE);
        }
    }

    @Override
    public Spannable getContentSummary(FileMessage data) {
        return new SpannableString(RongContext.getInstance()
                .getResources()
                .getString(R.string.de_plugins_file));
    }

    @Override
    public void onItemClick(View view, int position, FileMessage content, UIMessage message) {

    }

    @Override
    public void onItemLongClick(View view, int position, FileMessage content, UIMessage message) {

    }

    class ViewHolder {
        AsyncImageView img;
        TextView message;
    }


}

FileMessageProvider 負責控制 UI 展示樣式的類 此處就用一個文件樣式做展示,如果是發紅包可能資源圖片就會換成紅包樣式的圖片,還有上傳進度的 UI 展示也在本類


SendFileProvider

package io.rong.app.message.provider;

import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.util.Log;
import android.view.View;
import android.widget.Toast;

import java.io.File;

import io.rong.imkit.RongContext;
import io.rong.imkit.RongIM;
import io.rong.imkit.widget.provider.InputProvider;
import io.rong.imlib.RongIMClient;
import io.rong.imlib.model.Conversation;
import io.rong.imlib.model.Message;
import io.rong.message.FileMessage;

/**
 * Created by AMing on 15/12/24.
 * Company RongCloud
 */
public class SendFileProvider extends InputProvider.ExtendProvider {

    private static final String TAG = SendFileProvider.class.getSimpleName();
    private Context context;

    /**
     * 實例化適配器。
     *
     * @param context 融雲IM上下文。(通過 RongContext.getInstance() 可以獲取)
     */
    public SendFileProvider(RongContext context) {
        super(context);
        this.context = context;
    }

    @Override
    public Drawable obtainPluginDrawable(Context context) {
        return context.getResources().getDrawable(io.rong.imkit.R.drawable.rc_ic_picture);
    }

    @Override
    public CharSequence obtainPluginTitle(Context context) {
        return "文件";
    }

    @Override
    public void onPluginClick(View view) {
//        Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
//        intent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
//        startActivityForResult(intent, 1);
        Intent i = new Intent(Intent.ACTION_GET_CONTENT);
        i.setType("file/*");
        startActivityForResult(i, 1);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (data != null) {
            if (data.getData().getScheme().equals("file")) {
                String s = data.getData().getPath();
                Uri uri = data.getData();
                File file = new File(s);
                if (file.exists()) {
                    Log.e("file", "f是文件且存在");
                   Conversation conversation = getCurrentConversation();
                   sendFile(conversation.getConversationType(),conversation.getTargetId(),file,uri);
                } else {
                    Toast.makeText(context,"文件不存在",Toast.LENGTH_SHORT);
                }
            }

        }
    }

    private void sendFile(Conversation.ConversationType conversationType, String id, File file,Uri uri) {
        if (RongIM.getInstance()!= null && RongIM.getInstance().getRongIMClient() != null) {
            //TODO 文件消息

            Log.e("tag","");

            Uri themUri = Uri.parse("file:///sdcard/bob/bob.zip" );

//            Uri localUri = Uri.parse("file:///sdcard/bob/bob.zip");
            FileMessage fileMessage = FileMessage.obtain(uri,uri);
//            ImageMessage fileMessage = ImageMessage.obtain(themUri,localUri);

            RongIM.getInstance().getRongIMClient().sendImageMessage(Conversation.ConversationType.PRIVATE, id, fileMessage, null, null, new RongIMClient.SendImageMessageCallback() {
                @Override
                public void onAttached(Message message) {

                    Log.e(TAG, "-------------onAttached--------");
                }

                @Override
                public void onError(Message message, RongIMClient.ErrorCode code) {
                    Log.e(TAG, "----------------onError-----" + code);
                }

                @Override
                public void onSuccess(Message message) {
                    Log.e(TAG, "------------------onSuccess---");
                }

                @Override
                public void onProgress(Message message, int progress) {
                    Log.e(TAG, "-----------------onProgress----" + progress);

                }
            });
        }
    }
}

本類是發送文件的入口類,需要提醒的是. 此處代碼中是直接開啟的 Android 系統的文件管理器,在某些基於 Android 自定義的機型裡面打開沒有文件 建議用 Android原生機型 三星小米也都沒有問題. 這裡自己可以自定義掃描過濾寫自定義的文件管理器


Ohter Code:

三個核心類分享完了 我們再來說說其他相關代碼

application 類中注冊消息類型 和 注冊消息模板. 這步簡單但是很容易忘記
RongIM.registerMessageType(FileMessage.class);

RongIM.registerMessageTemplate(newFileMessageProvider());
點擊消息的監聽內判斷文件消息
if(message.getContent() instanceof FileMessage) {
            FileMessage fileMessage = (FileMessage) message.getContent();
            if (message.getMessageDirection().equals(io.rong.imlib.model.Message.MessageDirection.RECEIVE)) {
                Intent intent = new Intent(context, FileActivity.class);
                intent.putExtra("photo", fileMessage.getLocalUri() == null ? fileMessage.getRemoteUri() : fileMessage.getLocalUri());
                if (fileMessage.getThumUri() != null)
                    intent.putExtra("thumbnail", fileMessage.getThumUri());

                context.startActivity(intent);
            }
        }

此處判斷是文件消息然後跳轉至下載頁面下載


總結:

實現效果 和 實現原理 還有大概代碼都已經在上方分享,但是代碼建議大家不要全部 copy 有些東西還是需要自己理解後親自去實現. 例如上傳和下載的方法實現 這個是和你 服務端 或者 雲存儲交互的邏輯, 最後也希望這篇文章能夠幫助大家! End~

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved