RongExtension.this.setPluginBoard()方法;    this.mPluginToggle.setOnClickListener(new OnClickListener() {
            public void onClick(View v) {
                if(RongExtension.this.mExtensionClickListener != null) {
                    RongExtension.this.mExtensionClickListener.onPluginToggleClick(v, RongExtension.this);
                }
                RongExtension.this.setPluginBoard();
            }
        });   private void setPluginBoard() {
        if(this.mPluginAdapter.isInitialized()) {
            if(this.mPluginAdapter.getVisibility() == 0) {
              //省略部分代码
            } else {
             //省略部分代码
            }
        }  
    }   public void onAttachedToExtension(RongExtension extension) {
        this.mEditText = extension.getInputEditText();
        Context context = extension.getContext();
        RLog.i(TAG, "attach " + this.stack.size());
        //mEditText编辑框存放到stack栈对象中
        this.stack.push(this.mEditText);
        Resources resources = context.getResources();
        try {
            this.types = resources.getStringArray(resources.getIdentifier("rc_realtime_support_conversation_types", "array", context.getPackageName()));
        } catch (NotFoundException var5) {
            ;
        }
    }
    //判断栈大小,如果大于0出栈,并返回mEditText
    public void onDetachedFromExtension() {
        RLog.i(TAG, "detach " + this.stack.size());
        if(this.stack.size() > 0) {
            this.stack.pop();
            this.mEditText = this.stack.size() > 0?(EditText)this.stack.peek():null;
        }
    }getPluginModules方法主要把功能插件对象--实现IPluginModule接口存放到ArrayList中,提供给外部使用;*AMapNetworkLocationClient存在后才会把地理位置插件加到ArrayList;public List<IPluginModule> getPluginModules(ConversationType conversationType) {
        ArrayList pluginModuleList = new ArrayList();
        ImagePlugin image = new ImagePlugin();
        FilePlugin file = new FilePlugin();
        pluginModuleList.add(image);
        String e;
        Class cls;
        try {
            //判断高德定位服务类是否存在,存在的话根据ConversationType类型把位置共享插件与我的位置插件添加ArrayList中;
            e = "com.amap.api.netlocation.AMapNetworkLocationClient";
            cls = Class.forName(e);
            if(cls != null) {
                CombineLocationPlugin constructor = new CombineLocationPlugin();
                DefaultLocationPlugin recognizer = new DefaultLocationPlugin();
                boolean typesDefined = false;
                if(this.types != null && this.types.length > 0) {
                    String[] arr$ = this.types;
                    int len$ = arr$.length;
                    for(int i$ = 0; i$ < len$; ++i$) {
                        String type = arr$[i$];
                        if(conversationType.getName().equals(type)) {
                            typesDefined = true;
                            break;
                        }
                    }
                }
                if(typesDefined) {
                    pluginModuleList.add(constructor);
                } else if(this.types == null && conversationType.equals(ConversationType.PRIVATE)) {
                    pluginModuleList.add(constructor);
                } else {
                    pluginModuleList.add(recognizer);
                }
            }
        } catch (Exception var15) {
            RLog.i(TAG, "Not include AMap");
            var15.printStackTrace();
        }
        if(conversationType.equals(ConversationType.GROUP) || conversationType.equals(ConversationType.DISCUSSION) || conversationType.equals(ConversationType.PRIVATE)) {
            pluginModuleList.addAll(InternalModuleManager.getInstance().getExternalPlugins(conversationType));
        }
        pluginModuleList.add(file);
        //判断科大讯飞sdk是否存在,存在的话通过反射实例化语音识别插件并加入到ArraryList中
        try {
            e = "com.iflytek.cloud.SpeechUtility";
            cls = Class.forName(e);
            if(cls != null) {
                cls = Class.forName("io.rong.recognizer.RecognizePlugin");
                Constructor var16 = cls.getConstructor(new Class[0]);
                IPluginModule var17 = (IPluginModule)var16.newInstance(new Object[0]);
                pluginModuleList.add(var17);
            }
        } catch (Exception var14) {
            RLog.i(TAG, "Not include Recognizer");
            var14.printStackTrace();
        }
        return pluginModuleList;
    }mInitialized布尔类型值与addPlugins方法public class PluginAdapter {
    private static final String TAG = "PluginAdapter";
    private List<IPluginModule> mPluginModules = new ArrayList();
    private boolean mInitialized;
    public PluginAdapter() {
    }
    public boolean isInitialized() {
        return this.mInitialized;
    }
     //省略部分方法
    public void addPlugins(List<IPluginModule> plugins) {
        for(int i = 0; plugins != null && i < plugins.size(); ++i) {
            this.mPluginModules.add(plugins.get(i));
        }
    }
     //省略部分方法
    public void bindView(ViewGroup viewGroup) {
        this.mInitialized = true;
        this.initView(viewGroup.getContext(), viewGroup);
    }
    private void initView(Context context, ViewGroup viewGroup) {
     //省略部分方法
    }
    public int getVisibility() {
        return this.mPluginPager != null?this.mPluginPager.getVisibility():8;
    }
     //省略部分代码
}initPlugins方法把插件加到PluginAdapter对象中;
 2.接下来,重点分析是上面提到的setPluginBoard方法;长话多说,如果mPluginAdapter(插件适配器)未初始化,先进行初始化;
 否则,根据扩展面板是否显示,显示则隐藏键盘与扩展面板,隐藏的话显示扩展面板并隐藏表面面板与键盘;最后要做的是,把语音输入隐藏,mEditTextLayout布局显示; private void setPluginBoard() {
        if(this.mPluginAdapter.isInitialized()) {
            if(this.mPluginAdapter.getVisibility() == 0) {
                View pager = this.mPluginAdapter.getPager();
                if(pager != null) {
                    pager.setVisibility(pager.getVisibility() == 8?0:8);
                } else {
                    this.mPluginAdapter.setVisibility(8);
                    this.mContainerLayout.setSelected(true);
                    this.showInputKeyBoard();
                }
            } else {
                this.mEmoticonToggle.setImageResource(drawable.rc_emotion_toggle_selector);
                if(this.isKeyBoardActive()) {
                    this.getHandler().postDelayed(new Runnable() {
                        public void run() {
                            RongExtension.this.mPluginAdapter.setVisibility(0);
                        }
                    }, 200L);
                } else {
                    this.mPluginAdapter.setVisibility(0);
                }
                this.hideInputKeyBoard();
                this.hideEmoticonBoard();
                this.mContainerLayout.setSelected(false);
            }
        } else {
            this.mEmoticonToggle.setImageResource(drawable.rc_emotion_toggle_selector);
            this.mPluginAdapter.bindView(this);
            this.mPluginAdapter.setVisibility(0);
            this.mContainerLayout.setSelected(false);
            this.hideInputKeyBoard();
            this.hideEmoticonBoard();
        }
        this.hideVoiceInputToggle();
        this.mEditTextLayout.setVisibility(0);
    }getPluginModules方法提到的ImagePlugin类是讲解的重点;1 1.点击“+”的时候插件功能已经可以使用了,那么说明在聊天界面渲染之前插件已经被建立起来,很容易,想到初始化聊天IM服务是最好的时机;
//调用RongIM的public静态init方法,参数呢是实例化的DefaultExtensionModule
RongExtensionManager.getInstance().registerExtensionModule(new DefaultExtensionModule()); public void registerExtensionModule(IExtensionModule extensionModule) {
    if(mExtModules == null) {
        RLog.e("RongExtensionManager", "Not init in the main process.");
    } else if(extensionModule != null && !mExtModules.contains(extensionModule)) {
        RLog.i("RongExtensionManager", "registerExtensionModule " + extensionModule.getClass().getSimpleName());
        if(mExtModules.size() <= 0 || !((IExtensionModule)mExtModules.get(0)).getClass().getCanonicalName().equals("com.jrmf360.rylib.modules.JrmfExtensionModule") && !((IExtensionModule)mExtModules.get(0)).getClass().getCanonicalName().equals("com.melink.bqmmplugin.rc.BQMMExtensionModule")) {
            mExtModules.add(extensionModule);
        } else {
            mExtModules.add(0, extensionModule);
        }
        extensionModule.onInit(mAppKey);
    } else {
        RLog.e("RongExtensionManager", "Illegal extensionModule.");
    }
}2 2.再看RongExtension的initData方法,把RongExtensionManager中的List
private void initData() {
        this.mExtensionModuleList = RongExtensionManager.getInstance().getExtensionModules();
        this.mPluginAdapter = new PluginAdapter();//省略若干代码
}3 3.再看RongExtension的setConversation方法调用this.initPlugins(),当当当的,调用了实例化插件对象的addPlugins把插件加入到其中,从而形成关联;
   private void initPlugins() {
        Iterator i$ = this.mExtensionModuleList.iterator();
        while(i$.hasNext()) {
            IExtensionModule module = (IExtensionModule)i$.next();
            List pluginModules = module.getPluginModules(this.mConversationType);
            if(pluginModules != null && this.mPluginAdapter != null) {
                this.mPluginAdapter.addPlugins(pluginModules);
            }
        }
    }public interface IPluginModule {
    Drawable obtainDrawable(Context var1);
    String obtainTitle(Context var1);
    void onClick(Fragment var1, EditExtension var2);
    void onActivityResult(int var1, int var2, Intent var3);
}public class ImagePlugin implements IPluginModule {
ConversationType conversationType;
String targetId;
public ImagePlugin() {
}
//item的背景图片
public Drawable obtainDrawable(Context context) {
    return ContextCompat.getDrawable(context, R.drawable.rc_ext_plugin_image_selector);
}
//item的插件标题
public String obtainTitle(Context context) {
    return context.getString(R.string.rc_plugin_image);
}
//item点击事件
public void onClick(Fragment currentFragment, EditExtension extension) {
    String[] permissions = new String[]{"android.permission.READ_EXTERNAL_STORAGE"};
    //这里考虑android6.0权限变更,不仅需要声明权限,而且敏感权限需要允许时申请
    if(PermissionCheckUtil.requestPermissions(currentFragment, permissions)) {
        this.conversationType = extension.getConversationType();
        this.targetId = extension.getTargetId();
        Intent intent = new Intent(currentFragment.getActivity(), PictureSelectorActivity.class);
        //回调Fragment 中的onActivityResult
        extension.startActivityForPluginResult(intent, 23, this);
    }
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}public void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if(requestCode == 102) {
        this.getActivity().finish();
    } else {
        this.mRongExtension.onActivityPluginResult(requestCode, resultCode, data);
    }
}this.mFragment.startActivityForResult(intent, (position + 1 << 8) + (requestCode & 255));this.mExtensionClickListener.onImageResult(list, lat1);方法发送图片消息了,代码就不贴了;