Android Getting Started
手动登录
1.下载SDK并导入
打开你的工程,在工程的目录下配置gradle。
dependencies {
compile 'com.android.support:appcompat-v7:23.3.0'
compile 'com.android.support:design:23.3.0'
compile fileTree(dir: 'libs', include: '*.jar')
// 基础功能 (必需)
compile 'com.netease.nimlib:basesdk:3.5.5'
// 音视频需要
compile 'com.netease.nimlib:avchat:3.5.5'
// 聊天室需要
compile 'com.netease.nimlib:chatroom:3.5.5'
// 实时会话服务需要
compile 'com.netease.nimlib:rts:3.5.5'
// 全文检索服务需要
compile 'com.netease.nimlib:lucene:3.5.5'
}
2.配置AndroidManifest.xml
在你的工程下的AndroidManifest.xml
中加入以下配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxx">
<!-- 权限声明 -->
<!-- 访问网络状态-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 控制呼吸灯,振动器等,用于新消息提醒 -->
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 外置存储存取权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 多媒体相关 -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 如果需要实时音视频通话模块,下面的权限也是必须的。否则,可以不加 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- SDK 权限申明, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 -->
<!-- 和下面的 uses-permission 一起加入到你的 AndroidManifest 文件中。 -->
<permission
android:name="com.netease.nim.demo.permission.RECEIVE_MSG"
android:protectionLevel="signature"/>
<!-- 接收 SDK 消息广播权限, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 -->
<uses-permission android:name="com.netease.nim.demo.permission.RECEIVE_MSG"/>
<application
...>
<!-- APP key, 可以在这里设置,也可以在 SDKOptions 中提供。
如果 SDKOptions 中提供了,取 SDKOptions 中的值。 -->
<meta-data
android:name="com.netease.nim.appKey"
android:value="key_of_your_app" />
<!-- 声明云信后台服务,如需保持后台推送,使用独立进程效果会更好。 -->
<service
android:name="com.netease.nimlib.service.NimService"
android:process=":core"/>
<!-- 运行后台辅助服务 -->
<service
android:name="com.netease.nimlib.service.NimService$Aux"
android:process=":core"/>
<!-- 声明云信后台辅助服务 -->
<service
android:name="com.netease.nimlib.job.NIMJobService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":core"/>
<!-- 云信SDK的监视系统启动和网络变化的广播接收器,用户开机自启动以及网络变化时候重新登录,
保持和 NimService 同一进程 -->
<receiver android:name="com.netease.nimlib.service.NimReceiver"
android:process=":core"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<!-- 云信进程间通信 Receiver -->
<receiver android:name="com.netease.nimlib.service.ResponseReceiver"/>
<!-- 云信进程间通信service -->
<service android:name="com.netease.nimlib.service.ResponseService"/>
<!-- 安卓保活配置 -->
<service
android:name="com.netease.cosine.core.CosineService"
android:process=":cosine">
</service>
<receiver
android:name="com.netease.cosine.target.CosineReceiver"
android:exported="true"
android:process=":cosine">
</receiver>
<meta-data
android:name="com.netease.cosine.target"
android:value=""/>
<meta-data
android:name="com.netease.cosine.target.receiver"
android:value="com.netease.nimlib.service.NimReceiver"/>
</application>
</manifest>
3.在Application初始化SDK
在你的Application中的初始化SDK
public class NimApplication extends Application {
public void onCreate() {
super.onCreate();
//SDK初始化(启动后台服务,若已经存在用户登录信息,SDK将自动登录)
// 1.this 2.自动登录的参数 3.一些config
NIMClient.init(this, getLoginInfo(), getOptions());
}
4.创建XML文件并设置当前View
在你的工程中的src/res/layout下创建xml文件,并设置当前的View
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_marginTop="50dp"
android:layout_marginLeft="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:weightSum="1">
<TextView
android:text="用户名:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/name"
android:layout_weight="0"/>
<EditText
android:layout_marginLeft="10dp"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:ems="10"
android:id="@+id/account"
android:layout_weight="1.30" />
</LinearLayout>
<LinearLayout
android:layout_marginLeft="50dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView
android:text="密 码:"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView"
android:layout_weight="0"/>
<EditText
android:layout_marginLeft="10dp"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:ems="10"
android:id="@+id/passwd" />
</LinearLayout>
<LinearLayout
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/login"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Login"/>
</LinearLayout>
</LinearLayout>
5.在Activity初始化View的控件实现登录
创建LoginActivity并在activity中设置上一步的View,并且实现登录
public class LoginActivity extends Activity {
private EditText account;//用户名
private EditText passwd;//密码
private Button login;//登录
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.login);//设置第四步中的View
account = (EditText) findViewById(R.id.account);//初始化控件
passwd = (EditText)findViewById(R.id.passwd);//初始化控件
login = (Button) findViewById(R.id.login);//初始化控件
//实现Button的监听
login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
login();
}
});
}
private void login(){
final String name = account.getText().toString().toLowerCase();//获取edittext上用户输入的account
final String pwd = passwd.getText().toString();//获取edittext上用户输入的pwd
LoginInfo info = new LoginInfo(name,pwd); // config...
RequestCallback<LoginInfo> callback =
new RequestCallback<LoginInfo>() {
@Override
public void onSuccess(LoginInfo param) {
Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
finish();
}
@Override
public void onFailed(int code) {
Toast.makeText(LoginActivity.this,"登录失败: "+code,Toast.LENGTH_LONG).show();
}
@Override
public void onException(Throwable exception) {
}
};
NIMClient.getService(AuthService.class).login(info)
.setCallback(callback);//进行登录,实现登录的回调
}
}
自行集成SDK详解
云信Android SDK的要求
SDK最低要求Android 2.3
, 其中网络音视频通话和白板最低要求最低要求Android 4.0
。
开发者本身的开发环境检查
类库配置详解
静态导入SDK
网易云信 Android SDK v2.5及以上分为两种 SDK 包下载,第一种包含全部功能:IM + 聊天室 + 实时音视频 + 教学白板。第二种包含部分功能,包含:IM + 聊天室。
SDK 包的libs文件夹中,包含了网易云信的 jar 文件,各 jni 库文件夹以及 SDK 依赖的第三方库。
第一种,包含全部功能的 SDK 包。如果需用云信 SDK 提供的所有功能,将这些文件拷贝到你的工程的 libs 目录下,即可完成配置。列表如下:
libs
├── armeabi
│ ├── libne_audio.so (高清语音录制功能必须)
│ └── libcosine.so (Android 后台保活需要)
│ ├── libnrtc_engine.so (音视频需要)
│ └── libnrtc_network.so (音视频需要)
│ └── librts_network.so (实时会话服务需要)
├── armeabi-v7a
│ ├── libne_audio.so
│ └── libcosine.so
│ ├── libnrtc_engine.so
│ └── libnrtc_network.so
│ └── librts_network.so
├── x86
│ ├── libne_audio.so
│ └── libcosine.so
│ ├── libnrtc_engine.so
│ └── libnrtc_network.so
│ └── librts_network.so
├── nim-basesdk-1.0.0.jar (基础功能)
├── nim-chatroom-1.0.0.jar (聊天室需要)
├── nim-rts-1.0.0.jar (实时会话服务需要)
├── nim-avchat-1.0.0.jar (音视频需要)
├── nim-lucene-1.0.0.jar (全文检索需要)
├── nrtc-sdkjar(音视频需要)
└── cosinesdk.jar (Android 后台保活需要)
第二种,只包含 IM 基础功能和聊天室功能的 SDK 包。如果只需要 IM 基础功能和聊天室功能,只需要将下面这些文件拷贝到你的工程的 libs 目录下,即可完成配置。列表如下:
libs
├── armeabi
│ ├── libne_audio.so (高清语音录制功能必须)
│ └── libcosine.so (Android 后台保活需要)
├── armeabi-v7a
│ ├── libne_audio.so
│ └── libcosine.so
├── x86
│ ├── libne_audio.so
│ └── libcosine.so
├── nim-basesdk-1.0.0.jar (基础功能)
├── nim-chatroom-1.0.0.jar (聊天室需要)
└── cosinesdk.jar (Android 后台保活需要)
以上文件列表中,jar文件版本号可能会不同,子目录中的文件是 SDK 所依赖的各个 CPU 架构的 so 库。
按需配置jar包: 如果
不需要聊天室功能
,可以在IM和聊天室的基础包中,去掉nim-chatroom-1.0.0.jar
。 如果只需要 IM 基础功能和 音视频功能
,可以在IM和聊天室的基础包中,去掉nim-chatroom-1.0.0.jar
,so 库需要加上 libnrtc*.so
,还需加上nim-avchat-1.0.0.jar 和 nrtc-sdk.jar
; 如果不需要安卓保活功能
,可以去掉 libcosine.so 和 cosinesdk.jar
,以及assets 文件夹中的cosine文件夹
( AndroidManifest.xml 文件中相关的安卓保活的配置需要删去)。 如果不需要全文检索功能
,可以去掉 nim-lucene-1.0.0.jar
(该包有 1M+ 大小,如果没有用到消息全文检索功能,建议去掉)。
通过Gradle集成SDK(推荐)
简单,便捷。只需要简单的配置,gradle会自动去marven下载相应版本的aar,不需要手动配置jar。以后版本升级,只需要改动compile的版本号即可。
网易云信 Android SDK 2.5.0以上支持通过 Gradle 集成 SDK。
首先,在整个工程的 build.gradle 文件中,配置repositories,使用 jcenter 或者 maven ,二选一即可,如下:
allprojects {
repositories {
jcenter() // 或者 mavenCentral()
}
}
第二步,在主工程的 build.gradle 文件中,添加 dependencies。根据自己项目的需求,添加不同的依赖即可。注意:版本号必须一致,这里以1.0.0版本为例:
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
// 添加依赖。注意,版本号必须一致。
// 基础功能 (必需)
compile 'com.netease.nimlib:basesdk:1.0.0'
// 音视频需要
compile 'com.netease.nimlib:avchat:1.0.0'
// 聊天室需要
compile 'com.netease.nimlib:chatroom:1.0.0'
// 实时会话服务需要
compile 'com.netease.nimlib:rts:1.0.0'
// 全文检索服务需要
compile 'com.netease.nimlib:lucene:1.0.0'
}
再次注意:依赖包的版本号必须一致。
权限及组件详解
在 AndroidManifest.xml
中加入以下配置:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="xxx">
<!-- 权限声明 -->
<!-- 访问网络状态-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 控制呼吸灯,振动器等,用于新消息提醒 -->
<uses-permission android:name="android.permission.FLASHLIGHT" />
<uses-permission android:name="android.permission.VIBRATE" />
<!-- 外置存储存取权限 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 多媒体相关 -->
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<!-- 如果需要实时音视频通话模块,下面的权限也是必须的。否则,可以不加 -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
<uses-permission android:name="android.permission.BROADCAST_STICKY"/>
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- SDK 权限申明, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 -->
<!-- 和下面的 uses-permission 一起加入到你的 AndroidManifest 文件中。 -->
<permission
android:name="com.netease.nim.demo.permission.RECEIVE_MSG"
android:protectionLevel="signature"/>
<!-- 接收 SDK 消息广播权限, 第三方 APP 接入时,请将 com.netease.nim.demo 替换为自己的包名 -->
<uses-permission android:name="com.netease.nim.demo.permission.RECEIVE_MSG"/>
<application
...>
<!-- APP key, 可以在这里设置,也可以在 SDKOptions 中提供。
如果 SDKOptions 中提供了,取 SDKOptions 中的值。 -->
<meta-data
android:name="com.netease.nim.appKey"
android:value="key_of_your_app" />
<!-- 声明云信后台服务,如需保持后台推送,使用独立进程效果会更好。 -->
<service
android:name="com.netease.nimlib.service.NimService"
android:process=":core"/>
<!-- 运行后台辅助服务 -->
<service
android:name="com.netease.nimlib.service.NimService$Aux"
android:process=":core"/>
<!-- 声明云信后台辅助服务 -->
<service
android:name="com.netease.nimlib.job.NIMJobService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE"
android:process=":core"/>
<!-- 云信SDK的监视系统启动和网络变化的广播接收器,用户开机自启动以及网络变化时候重新登录,
保持和 NimService 同一进程 -->
<receiver android:name="com.netease.nimlib.service.NimReceiver"
android:process=":core"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
<!-- 云信进程间通信 Receiver -->
<receiver android:name="com.netease.nimlib.service.ResponseReceiver"/>
<!-- 云信进程间通信service -->
<service android:name="com.netease.nimlib.service.ResponseService"/>
<!-- 安卓保活配置 -->
<service
android:name="com.netease.cosine.core.CosineService"
android:process=":cosine">
</service>
<receiver
android:name="com.netease.cosine.target.CosineReceiver"
android:exported="true"
android:process=":cosine">
</receiver>
<meta-data
android:name="com.netease.cosine.target"
android:value=""/>
<meta-data
android:name="com.netease.cosine.target.receiver"
android:value="com.netease.nimlib.service.NimReceiver"/>
</application>
</manifest>
cosine提供的保活,主要针对Android 5以下的设备。
- 对于android5.0以下系统,云信的保活机制可做到只要用户运行过,如果后面集成云信SDK的app被杀死(包括情形:在后台时被系统kill,用户手动移除最近任务时被kill,用户在应用信息页面主动force stop,应用程序崩溃等),app能在指定延迟时间内重启。重启后如果网络通畅,即可及时收到推送消息。
- 对于5.0及以上的系统,如果用户没有在应用信息页面主动force stop, 集成云信SDK的app能在进程退出后一段时间内(最长不超过10分钟)重启。如果用户主动force stop,则无法再收到推送。
- 如果用户手机上安装有易信等网易系app,或者安装了其他集成了云信SDK的app,那么只要有一个这样的app存留,可无视上面的2条,无论什么系统,都可以保证其他的集成云信SDK的app能及时收到推送。
初始化SDK详解
在你的程序的 Application 的 onCreate
中,加入网易云信 SDK 的初始化代码:
public class NimApplication extends Application {
public void onCreate() {
// ... your codes
// SDK初始化(启动后台服务,若已经存在用户登录信息, SDK 将完成自动登录)
NIMClient.init(this, loginInfo(), options());
// ... your codes
if (inMainProcess()) {
// 注意:以下操作必须在主进程中进行
// 1、UI相关初始化操作
// 2、相关Service调用
// 3、任何第三方初始化请放在主进程里面,否则会造成登录没有回调
}
}
// 如果返回值为 null,则全部使用默认参数。
private SDKOptions options() {
SDKOptions options = new SDKOptions();
// 如果将新消息通知提醒托管给 SDK 完成,需要添加以下配置。否则无需设置。
StatusBarNotificationConfig config = new StatusBarNotificationConfig();
config.notificationEntrance = WelcomeActivity.class; // 点击通知栏跳转到该Activity
//状态栏提醒的小图标的资源ID,没有的话请置于0
config.notificationSmallIconId = R.drawable.ic_stat_notify_msg;
// 呼吸灯配置
config.ledARGB = Color.GREEN;
config.ledOnMs = 1000;
config.ledOffMs = 1500;
// 通知铃声的uri字符串
config.notificationSound = "android.resource://com.netease.nim.demo/raw/msg";
options.statusBarNotificationConfig = config;
// 配置保存图片,文件,log 等数据的目录
// 如果 options 中没有设置这个值,SDK 会使用下面代码示例中的位置作为 SDK 的数据目录。
// 该目录目前包含 log, file, image, audio, video, thumb 这6个目录。
// 如果第三方 APP 需要缓存清理功能, 清理这个目录下面个子目录的内容即可。
String sdkPath = Environment.getExternalStorageDirectory() + "/" + getPackageName() + "/nim";
options.sdkStorageRootPath = sdkPath;
// 配置是否需要预下载附件缩略图,默认为 true
options.preloadAttach = true;
// 配置附件缩略图的尺寸大小。表示向服务器请求缩略图文件的大小
// 该值一般应根据屏幕尺寸来确定, 默认值为 Screen.width / 2
options.thumbnailSize = ${Screen.width} / 2;
// 用户资料提供者, 目前主要用于提供用户资料,用于新消息通知栏中显示消息来源的头像和昵称
options.userInfoProvider = new UserInfoProvider() {
@Override
public UserInfo getUserInfo(String account) {
return null;
}
@Override
public int getDefaultIconResId() {
//用户资料提供者中的默认头像资源ID,没有直接返回0
return R.drawable.avatar_def;
}
@Override
public Bitmap getTeamIcon(String tid) {
return null;
}
@Override
public Bitmap getAvatarForMessageNotifier(String account) {
return null;
}
@Override
public String getDisplayNameForMessageNotifier(String account, String sessionId,
SessionTypeEnum sessionType) {
return null;
}
};
return options;
}
// 如果已经存在用户登录信息,返回LoginInfo,否则返回null即可
private LoginInfo loginInfo() {
return null;//如需自动登录,请自行参考Demo中的自动登录代码
}
}
特别提醒:SDK 的初始化方法必须在主进程中调用,在非主进程中初始化无效。请在主进程中调用 SDK XXXService 提供的方法,在主进程中注册 XXXServiceObserver的观察者(有事件变更,会回调给主进程的主线程)。
如果你的模块运行在非主进程,请自行实现主进程与非主进程的通信(Binder/AIDL/BroadcastReceiver等IPC)将主进程回调或监听返回的数据传递给非主进程。
再次提醒: 请不要在 SDK 进程中调用各种 Service 提供的接口,也不要在 SDK 进程中做 UI 相关的初始化动作,以免造成资源浪费。判断当前进程是否是在主进程的代码如下:
public static boolean inMainProcess(Context context) {
String packageName = context.getPackageName();
String processName = SystemUtil.getProcessName(context);
return packageName.equals(processName);
}
/**
* 获取当前进程名
* @param context
* @return 进程名
*/
public static final String getProcessName(Context context) {
String processName = null;
// ActivityManager
ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE));
while (true) {
for (ActivityManager.RunningAppProcessInfo info : am.getRunningAppProcesses()) {
if (info.pid == android.os.Process.myPid()) {
processName = info.processName;
break;
}
}
// go home
if (!TextUtils.isEmpty(processName)) {
return processName;
}
// take a rest and again
try {
Thread.sleep(100L);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
实现手动登录详解
Tip: 手动登录的一些详细场景请参考Android开发文档手动登录
private void login(){
//获取edittext上用户输入的account
final String name = account.getText().toString().toLowerCase();
//获取edittext上用户输入的pwd
final String pwd = passwd.getText().toString();
LoginInfo info = new LoginInfo(name,pwd); // config...
RequestCallback<LoginInfo> callback =
new RequestCallback<LoginInfo>() {
@Override
public void onSuccess(LoginInfo param) {
// 可以在此保存LoginInfo到本地,下次启动APP做自动登录用
Toast.makeText(LoginActivity.this, "登录成功", Toast.LENGTH_SHORT).show();
MainActivity.start(LoginActivity.this);
finish();
}
@Override
public void onFailed(int code) {
Toast.makeText(LoginActivity.this,"登录失败: "+code,Toast.LENGTH_LONG).show();
}
@Override
public void onException(Throwable exception) {
}
};
NIMClient.getService(AuthService.class).login(info)
.setCallback(callback);//进行登录,实现登录的回调
}
登录成功后,可以在onSuccess中进行其他的操作,并且可以将用户登录信息 LoginInfo 信息保存到本地,下次启动APP时,读取本地保存的 LoginInfo 进行自动登录。
说明:在手动登录过程中,如果网络断开或者与云信服务器建立连接失败,会返回登录失败(错误码 415),在线状态切换为 NET_BROKEN;如果连接建立成功,SDK 发出登录请求后云信服务器一直没有响应,那么 30s 后将导致登录超时,那么会返回登录失败(错误码 408),在线状态切换为 UNLOGIN。
基于Demo开发
Demo及SDK、UIKIT下载
- Demo和SDK下载请参考网易云信官网
- Android开发手册
- Android API
- Android的UI开源库
工程指引
Eclipse导入Demo(2.4版本以下Demo支持导入,如需,请联系技术支持)
注:以下需要开发者自行解决:导入uikit之后,会用到support包,我们用的是v7-23 support包。如果需要兼容不同版本的主题,请开发者自行完成