一、前言

最近看到有许多人在说根据环信官方文档导入 EaseUI 会出现各种错误,由于官方(此处和谐省略一万字), 顺便学学新的 add dependencies 方式,记录一下, Android Studio 3.3 add dependencies 方式又改了。

二、运行环境

Android Studio 版本 : 3.3 Canary 5

!

环信 SDK 版本 : easemob-sdk-3.5.0

三、导入 EaseUI

先新建个项目

下载 easemob-sdk 里面带有 EaseUI

导入这个 easeui

File -> New -> Import Module

选择 easeui 所在的路径

点击 Finish

导入之后会有红色的提示,四个都只是 WARNING,把四个 WANRNING 解决掉

第一个 WANRNING,是 Build Tools 的问题,Android Studio 3.3.0-alpha05 最低支持的 Build Tools 版本是 27.0.3 ,把 easeui 的 build.gradle 的 buildToolsVersion 改为 27.0.3 顺便把 compileSdkVersion 和 targetSdkVersion 也改为 27,同步一下 gradle,第一个 WANRNING 已经没了

后三个 WANRNING,是 AndroidStudio 3.0 之后的问题,
compile 改为 implementation 或 api,
implementation 和 api 是有区别的,implementation 是指这个导入的 Library 是 Module 内部使用的,别的 Module 导入当前这个 Module 就用不了当前 Module 导入的 Library 的东西,api 是指别的 Module 导入当前这个 Module 后仍然能够使用当前 Module 导入的 Library 的东西,
testCompile 改为 testImplementation,
androidTestCompile 改为 androidTestImplementation,

由于 easeui 的 libs 文件夹里有环信的 hyphenatechat_3.5.0.jar ,由于 app 里要用到 hyphenatechat 里的东西,所以 fileTree() 要用 api 而不是 implementation,改完后同步一下 gradle,剩下的三个 WANRNING 都没了

接下来 app 添加上 easeui 这个 Module ,在项目右键 Open Module Settings

选择 Dependencies,Modules 选择 app,Declared dependencies 点击 + 号

上面 step 1 的 easeui 打上勾,Step 2 选 implementation,点击 OK,再点 Apply 或 OK

由于 AndroidStudio 3.2 起开始推荐使用 androidx, 但 easeui 里用的是 android, 所以会报错,要么把 easeui 里的改为 androidx 要么不使用 androidx,改 easeui 的话那就太多要改的了,不使用 androidx 了,

打开 gradle.properties 注释掉 android.useAndroidX=true 和 android.enableJetifier=true

打开 app 的 build.gradle 也要改,compileSdkVersion, buildToolsVersion, targetSdkVersion 那些改和 easeui 一样的,dependencies androidx 的改为 android 的,改完同步一下 gradle, 由于去掉了 androidx, Activity 里的 AppCompatActivity 和 布局里的 ConstraintLayout 也要改为 android 的而不是 androidx 的

看起来好像没什么问题了,先运行一下,

出问题了,support v4 包没有 AsyncTaskCompat 这个类了,打开 EaseChatRowImage.java 这个类

去掉 AsyncTaskCompat,改直接执行 AsyncTask ,

再运行一下,可以运行起来

四、初始化 easeui

虽然导入了 easeui, 但 easeui 还没在 app 里初始化和用起来,先初始化 easeui
新建个 App 类继承 Application,然后在 AndroidManifest 里设置

public class App extends Application {    @Override    public void onCreate() {        super.onCreate();        initEaseUi();    }    private void initEaseUi() {        EMOptions emOptions = new EMOptions();        emOptions.setAcceptInvitationAlways(false);        EaseUI.getInstance().init(this, new EMOptions());    }}

再运行一次 , 报错了,看下 Log

说没有在 AndroidManifest 里设置 APPKEY,那就设置一下了,可参考官方的 环信官方配置工程

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    package="com.ce.easeuitest">        <uses-permission android:name="android.permission.VIBRATE" />    <uses-permission android:name="android.permission.INTERNET" />    <uses-permission android:name="android.permission.RECORD_AUDIO" />    <uses-permission android:name="android.permission.CAMERA" />    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />    <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" />    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />    <uses-permission android:name="android.permission.GET_TASKS" />    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />    <uses-permission android:name="android.permission.WAKE_LOCK" />    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />    <uses-permission android:name="android.permission.READ_PHONE_STATE" />    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />    <application        android:name=".App"        android:allowBackup="true"        android:icon="@mipmap/ic_launcher"        android:label="@string/app_name"        android:roundIcon="@mipmap/ic_launcher_round"        android:supportsRtl="true"        android:theme="@style/AppTheme"        tools:ignore="GoogleAppIndexingWarning">                <meta-data android:name="EASEMOB_APPKEY"  android:value="1111180606228105#easeuitest" />                <service android:name="com.hyphenate.chat.EMChatService" android:exported="true"/>        <service android:name="com.hyphenate.chat.EMJobService"            android:permission="android.permission.BIND_JOB_SERVICE"            android:exported="true"            />                <receiver android:name="com.hyphenate.chat.EMMonitorReceiver">            <intent-filter>                <action android:name="android.intent.action.PACKAGE_REMOVED"/>                <data android:scheme="package"/>            intent-filter>                        <intent-filter>                <action android:name="android.intent.action.BOOT_COMPLETED"/>                <action android:name="android.intent.action.USER_PRESENT" />            intent-filter>        receiver>        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            intent-filter>        activity>    application>manifest>

再运行一次, 可以运行起来,再看 log 没有问题

五、简单使用 easeui

做个登录功能测试一下,新建个 LoginActivity

修改一下 LoginActivity 的代码逻辑并实现登录操作,为了直接点,这里就在 Activity 里去开启线程做登录操作了

/** * A login screen that offers login via email/password. */public class LoginActivity extends AppCompatActivity{    // UI references.    private AutoCompleteTextView mEmailView;    private EditText mPasswordView;    private View mProgressView;    private View mLoginFormView;    private Handler mHandler = new Handler();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_login);        // Set up the login form.        mEmailView = (AutoCompleteTextView) findViewById(R.id.email);        mPasswordView = (EditText) findViewById(R.id.password);        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {            @Override            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {                if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {                    attemptLogin();                    return true;                }                return false;            }        });        Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);        mEmailSignInButton.setOnClickListener(new OnClickListener() {            @Override            public void onClick(View view) {                attemptLogin();            }        });        mLoginFormView = findViewById(R.id.login_form);        mProgressView = findViewById(R.id.login_progress);    }    @Override    protected void onDestroy() {        mHandler.removeCallbacksAndMessages(null);        super.onDestroy();    }    /**     * Attempts to sign in or register the account specified by the login form.     * If there are form errors (invalid email, missing fields, etc.), the     * errors are presented and no actual login attempt is made.     */    private void attemptLogin() {        // Reset errors.        mEmailView.setError(null);        mPasswordView.setError(null);        // Store values at the time of the login attempt.        String email = mEmailView.getText().toString();        String password = mPasswordView.getText().toString();        boolean cancel = false;        View focusView = null;        // Check for a valid password, if the user entered one.        if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {            mPasswordView.setError(getString(R.string.error_invalid_password));            focusView = mPasswordView;            cancel = true;        }        // Check for a valid email address.        if (TextUtils.isEmpty(email)) {            mEmailView.setError(getString(R.string.error_field_required));            focusView = mEmailView;            cancel = true;        } else if (!isEmailValid(email)) {            mEmailView.setError(getString(R.string.error_invalid_email));            focusView = mEmailView;            cancel = true;        }        if (cancel) {            // There was an error; don't attempt login and focus the first            // form field with an error.            focusView.requestFocus();        } else {            // Show a progress spinner, and kick off a background task to            // perform the user login attempt.            showProgress(true);            // 开启线程去做登录操作            new LoginThread(email, password).start();        }    }    private boolean isEmailValid(String email) {        return email.length() > 4;    }    private boolean isPasswordValid(String password) {        return password.length() > 4;    }    /**     * Shows the progress UI and hides the login form.     */    @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)    private void showProgress(final boolean show) {        // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow        // for very easy animations. If available, use these APIs to fade-in        // the progress spinner.        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {            int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);            mLoginFormView.animate().setDuration(shortAnimTime).alpha(                    show ? 0 : 1).setListener(new AnimatorListenerAdapter() {                @Override                public void onAnimationEnd(Animator animation) {                    mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);                }            });            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);            mProgressView.animate().setDuration(shortAnimTime).alpha(                    show ? 1 : 0).setListener(new AnimatorListenerAdapter() {                @Override                public void onAnimationEnd(Animator animation) {                    mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);                }            });        } else {            // The ViewPropertyAnimator APIs are not available, so simply show            // and hide the relevant UI components.            mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);            mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);        }    }    private class LoginThread extends Thread {        String username;        String password;        public LoginThread(String username, String password) {            this.username = username;            this.password = password;        }        @Override        public void run() {            EMClient.getInstance().login(username, password, new EMCallBack() {                @Override                public void onSuccess() {                    mHandler.post(new Runnable() {                        @Override                        public void run() {                            showProgress(false);                            // 登录成功跳转去 MainActivity                            Intent intent = new Intent(LoginActivity.this, MainActivity.class);                            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);                            startActivity(intent);                            finish();                        }                    });                }                @Override                public void onError(int i, String s) {                    mHandler.post(new Runnable() {                        @Override                        public void run() {                            // 登录失败                            showProgress(false);                            mPasswordView.setError(getString(R.string.error_invalid_password));                            View focusView = mPasswordView;                            focusView.requestFocus();                        }                    });                }                @Override                public void onProgress(int i, String s) {                }            });        }    }}

修改下 Manifest,让 LoginActivity 先运行

<activity    android:name=".LoginActivity"    android:label="@string/title_activity_login">    <intent-filter>        <action android:name="android.intent.action.MAIN" />        <category android:name="android.intent.category.LAUNCHER" />    intent-filter>activity>

由于登录后跳转到 MainActivity ,那就简单地在 MainActivity 做个联系人列表显示,
新建个 ContactFragment 类继承 EaseContactListFragment,这里也简单点,用个 AsyncTask 去获取所有的联系人然后显示出来,

public class ContactFragment extends EaseContactListFragment {    @Override    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        new GetContact().execute();    }    private class GetContact extends AsyncTask<Void, Void, Map<String, EaseUser>> {        @Override        protected Map doInBackground(Void... voids) {            try {                Map contactMap = new HashMap<>();                List contacts = EMClient.getInstance().contactManager().getAllContactsFromServer();                for (String contact : contacts) {                    EaseUser easeUser = new EaseUser(contact);                    contactMap.put(contact, easeUser);                }                return contactMap;            } catch (HyphenateException e) {                e.printStackTrace();            }            return null;        }        @Override        protected void onPostExecute(Map easeUserMap) {            if (easeUserMap != null && !easeUserMap.isEmpty()) {                setContactsMap(easeUserMap);                refresh();            }        }    }}

把 ContactFragment 放到 MainActivity 去显示,

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        FragmentManager fragmentManager = getSupportFragmentManager();        fragmentManager.beginTransaction()                .replace(R.id.lay_content, new ContactFragment())                .commitNowAllowingStateLoss();    }}

一切准备就绪,等等,还有账号还没准备,先注册几个账号,

添加几个好友进去

运行起来看看吧,可以登录并获取到所有联系人

六、后记

导入 easeui 确实有几个坑的地方,不过没多坑,Android Studio 3.3 的 add dependencies 方式感觉更加友好了。

本文源码

更多相关文章

  1. Android面试系列文章2018之Java部分类加载器篇
  2. Android防止崩溃的库,有效的降低Crash率
  3. Android高手进阶教程(十)之----Android(安卓)PopupWindow的使用!
  4. Android(安卓)使用Rtmp音视频推流
  5. Android中xml解析--实现软件升级功能
  6. [置顶] Android(安卓)WebKit消息处理
  7. Android(安卓)原生控件ViewFlipper实现淘宝头条垂直滚动广告条
  8. (原创)Android入门教程(三十六)------实现手机联系人的全选
  9. Android官方开发文档Training系列课程中文版:Android的安全建议

随机推荐

  1. Android 一个程序A启动程序B
  2. 如何获取Android IP地址
  3. Bugly对应用进行升级
  4. android点击屏幕隐藏小键盘
  5. android 使用imageloader 获取图片时,如果
  6. Android 知识点收藏
  7. 为android写的一个UDP Socket连接组件
  8. Android——常用代码段积累(一)
  9. Android 如何在代码中将PX转换成DIP
  10. Android内存泄露资料