基于生活物联网平台的账号及用户SDK,您可以自定义自有品牌App的开放账号OA(Open Account)模块相关的用户界面UI(User Interface),主要包括登录页面、注册页面、密码重置页面等。
定制项
Android App的OA UI定制项如下。
App界面图示 |
可定制内容 |
 |
修改原生元素
- 显示手机区号(图示中②)
- 修改登录和注册按钮的颜色(图示中③)
- 修改现有控件的事件
- 修改登录超限提示信息样式(图示中④)
|
新增元素
|
说明 Android不支持客户端修改失败提示信息,且不支持对现有控件增加自定义事件。您仅可以修改现有控件的事件或新增控件来自定义事件。
显示手机区号
登录和注册页面中的手机区号默认不显示,如果您需要显示手机区号,如+86,请根据以下内容来操作。
在App工程中添加以下代码,并通过设置supportForeignMobileNumbers参数的值来控制手机区号的显示和隐藏。
//登录页显示手机区号
OpenAccountUIConfigs.AccountPasswordLoginFlow.supportForeignMobileNumbers=true; //true为显示,false为隐藏
//忘记密码页显示手机区号
OpenAccountUIConfigs.MobileResetPasswordLoginFlow.supportForeignMobileNumbers=true; //true为显示,false为隐藏
修改登录和注册按钮的颜色
登录和注册按钮默认为浅灰色,如果您需要修改App登录和注册按钮的颜色,请根据以下步骤来操作。
- 在代码工程的styles.xml中新增一个style。
- 修改style中登录和注册按钮的颜色,其对应的参数为ali_sdk_openaccount_attrs_next_step_bg。
<style name="NewLogin" parent="@style/Login">
//修改item属性的值
<item name="ali_sdk_openaccount_attrs_next_step_bg">@color/color_1FC88B</item>
</style>
- 修改AndroidManifest中的activity的主题配置,使设置的颜色生效。
//AndroidManifest中的activity的主题配置修改
<activity
android:name="com.aliyun.iot.ilop.demo.page.login3rd.OALoginActivity"
android:configChanges="orientation|screenSize|keyboardHidden|locale|layoutDirection|keyboard"
android:theme="@style/NewLogin" />
修改现有控件的事件
如果您需要修改现有控件的事件,只需重新设置控件事件即可。以重写登录界面中的登录事件为例,即重新定义下图所示内容。
修改登录超限提示信息样式
登录App时,如果输入登录密码的次数达到上限,App会限制继续操作,并提示重置密码。如果您需要修改该失败提示对话框的样式,只需修改toastUtils.alert()
即可。
- 重写
toastUtils.alert()
的代码。
//OALoginActivity中的LoginTask
protected class LoginTask extends TaskWithDialog<Void, Void, Result<LoginResult>> {
private String loginId;
private String password;
private String sig;
private String nocToken;
private String cSessionId;
public LoginTask(Activity activity, String loginId, String password, String sig, String nocToken, String cSessionId) {
super(activity);
this.loginId = loginId;
this.password = password;
this.sig = sig;
this.nocToken = nocToken;
this.cSessionId = cSessionId;
}
protected Result<LoginResult> asyncExecute(Void... params) {
Map<String, Object> loginRequest = new HashMap();
if (this.loginId != null) {
loginRequest.put("loginId", this.loginId);
}
if (this.password != null) {
try {
String rsaKey = RSAKey.getRsaPubkey();
if (TextUtils.isEmpty(rsaKey)) {
return null;
}
loginRequest.put("password", Rsa.encrypt(this.password, rsaKey));
} catch (Exception var4) {
return null;
}
}
LoginActivity.this.hideSoftInputForHw();
Result result;
if (!CommonUtils.isNetworkAvailable()) {
if (ConfigManager.getInstance().isSupportOfflineLogin()) {
return LoginActivity.this.tryOfflineLogin(this.loginId, this.password);
} else {
result = new Result();
result.code = 10014;
result.message = MessageUtils.getMessageContent(10014, new Object[0]);
return result;
}
} else {
if (this.sig != null) {
loginRequest.put("sig", this.sig);
}
if (!TextUtils.isEmpty(this.cSessionId)) {
loginRequest.put("csessionid", this.cSessionId);
}
if (!TextUtils.isEmpty(this.nocToken)) {
loginRequest.put("nctoken", this.nocToken);
}
result = OpenAccountUtils.toLoginResult(RpcUtils.pureInvokeWithRiskControlInfo("loginRequest", loginRequest, "login"));
return ConfigManager.getInstance().isSupportOfflineLogin() && result.code == 10019 ? LoginActivity.this.tryOfflineLogin(this.loginId, this.password) : result;
}
}
protected void doWhenException(Throwable t) {
this.executorService.postUITask(new Runnable() {
public void run() {
ToastUtils.toastSystemError(LoginTask.this.context);
}
});
}
protected void onPostExecute(Result<LoginResult> result) {
this.dismissProgressDialog();
super.onPostExecute(result);
try {
if (result == null) {
if (ConfigManager.getInstance().isSupportOfflineLogin()) {
ToastUtils.toastNetworkError(this.context);
} else {
ToastUtils.toastSystemError(this.context);
}
} else {
android.net.Uri.Builder builder;
Intent h5Intent;
String accountName;
switch(result.code) {
case 1:
if (result.data != null && ((LoginResult)result.data).loginSuccessResult != null) {
SessionData sessionData = OpenAccountUtils.createSessionDataFromLoginSuccessResult(((LoginResult)result.data).loginSuccessResult);
if (sessionData.scenario == null) {
sessionData.scenario = 1;
}
LoginActivity.this.sessionManagerService.updateSession(sessionData);
accountName = ((LoginResult)result.data).userInputName;
if (TextUtils.isEmpty(accountName)) {
accountName = this.loginId;
}
if (ConfigManager.getInstance().isSupportOfflineLogin()) {
OpenAccountSDK.getSqliteUtil().saveToSqlite(this.loginId, this.password);
}
boolean isExist = LoginActivity.this.loginIdEdit.saveInputHistory(accountName);
if (AccountPasswordLoginFlow.showTipAlertAfterLogin && !isExist) {
String message = ResourceUtils.getString(LoginActivity.this.getApplicationContext(), "ali_sdk_openaccount_dynamic_text_alert_msg_after_login");
LoginActivity.this.showTipDialog(String.format(message, this.loginId));
} else {
LoginActivity.this.loginSuccess();
}
return;
}
break;
case 2:
SessionData sessionData1 = OpenAccountUtils.createSessionDataFromLoginSuccessResult(((LoginResult)result.data).loginSuccessResult);
if (sessionData1.scenario == null) {
sessionData1.scenario = 1;
}
LoginActivity.this.sessionManagerService.updateSession(sessionData1);
LoginActivity.this.loginSuccess();
break;
case 4037:
if (AccountPasswordLoginFlow.showAlertForPwdErrorToManyTimes) {
String postive = LoginActivity.this.getResources().getString(string.ali_sdk_openaccount_text_confirm);
accountName = LoginActivity.this.getResources().getString(string.ali_sdk_openaccount_text_reset_password);
final ToastUtils toastUtils = new ToastUtils();
android.content.DialogInterface.OnClickListener postiveListener = new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
toastUtils.dismissAlertDialog(LoginActivity.this);
}
};
android.content.DialogInterface.OnClickListener negativeListener = new android.content.DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
LoginActivity.this.forgetPassword((View)null);
}
};
//重写toastUtils类的alert()方法
toastUtils.alert(LoginActivity.this, "", result.message, postive, postiveListener, accountName, negativeListener);
} else {
ToastUtils.toast(this.context, result.message, result.code);
}
break;
case 26053:
if (result.data != null && ((LoginResult)result.data).checkCodeResult != null && !TextUtils.isEmpty(((LoginResult)result.data).checkCodeResult.clientVerifyData)) {
builder = Uri.parse(((LoginResult)result.data).checkCodeResult.clientVerifyData).buildUpon();
builder.appendQueryParameter("callback", "https://www.alipay.com/webviewbridge");
h5Intent = new Intent(LoginActivity.this, LoginDoubleCheckWebActivity.class);
h5Intent.putExtra("url", builder.toString());
h5Intent.putExtra("title", result.message);
h5Intent.putExtra("callback", "https://www.alipay.com/webviewbridge");
LoginActivity.this.startActivityForResult(h5Intent, RequestCode.NO_CAPTCHA_REQUEST_CODE);
return;
}
break;
case 26152:
if (result.data != null && ((LoginResult)result.data).checkCodeResult != null && !TextUtils.isEmpty(((LoginResult)result.data).checkCodeResult.clientVerifyData)) {
builder = Uri.parse(((LoginResult)result.data).checkCodeResult.clientVerifyData).buildUpon();
builder.appendQueryParameter("callback", "https://www.alipay.com/webviewbridge");
h5Intent = new Intent(LoginActivity.this, LoginIVWebActivity.class);
h5Intent.putExtra("url", builder.toString());
h5Intent.putExtra("title", result.message);
h5Intent.putExtra("callback", "https://www.alipay.com/webviewbridge");
LoginActivity.this.startActivityForResult(h5Intent, RequestCode.RISK_IV_REQUEST_CODE);
}
break;
default:
if (TextUtils.equals(result.type, "CALLBACK") && LoginActivity.this.getLoginCallback() != null) {
LoginActivity.this.getLoginCallback().onFailure(result.code, result.message);
return;
}
LoginActivity.this.onPwdLoginFail(result.code, result.message);
}
}
} catch (Throwable var8) {
AliSDKLogger.e("oa", "after post execute error", var8);
ToastUtils.toastSystemError(this.context);
}
}
}
- 定制弹出的对话框,并显示
result.message
的错误信息。
toastUtils.alert(LoginActivity.this, "", result.message, postive, postiveListener, accountName, negativeListener);
新增控件和单击事件
当您需要在App中新增一个控件,并添加相应的单击事件时,可以根据以下步骤来操作。
- 在界面上新增一个控件,并在重写的xml文件中添加控件信息。
- 在activity中添加该控件的单击事件。
新增邮箱登录方式
如果您需要App支持通过邮箱方式登录,您需要开发邮箱相关的功能,包括邮箱登录(图示中①)、邮箱注册(图示中②)、邮箱重置密码(图示中③)等。
- 在App登录页面增加邮箱登录的方式。
Android账号及用户SDK的OALoginActivity已默认支持手机号登录和邮箱登录。此时您只需要将手机区号隐藏,并修改登录提示即可。
- 隐藏手机区号。
//隐藏手机区号
OpenAccountUIConfigs.AccountPasswordLoginFlow.supportForeignMobileNumbers = false;
- 修改邮箱登录信息。
//修改登录提示信息
this.loginIdEdit.getEditText().setHint("请输入手机号或邮箱账号");
- 新增邮箱注册功能。
- 在登录页面增加邮箱注册按钮。
请参见本文档中新增控件和单击事件来实现。
- 定义注册的回调函数。
//注册的回调函数
private EmailRegisterCallback getEmailRegisterCallback() {
return new EmailRegisterCallback() {
@Override
public void onSuccess(OpenAccountSession session) {
//注册成功
}
@Override
public void onFailure(int code, String message) {
//注册失败
}
@Override
public void onEmailSent(String email) {
}
};
}
- 跳转到邮箱注册界面。
//跳转到邮箱注册界面
OpenAccountUIService openAccountUIService = OpenAccountSDK.getService(OpenAccountUIService.class);
openAccountUIService.showEmailRegister(OALoginActivity.this, getEmailRegisterCallback());
- 新增邮箱重置密码功能。
通过邮箱方式登录App时,如果忘记了邮箱注册的密码,需要通过邮箱重置密码的功能来找回密码。
- 在登录页面增加邮箱找回按钮。
请参见本文档中新增控件和单击事件来实现。
- 定义邮箱密码找回的回调方法。
private EmailResetPasswordCallback getEmailResetPasswordCallback() {
return new EmailResetPasswordCallback() {
@Override
public void onSuccess(OpenAccountSession session) {
//修改成功
}
@Override
public void onFailure(int code, String message) {
//修改失败
}
@Override
public void onEmailSent(String email) {
//发送验证码邮件
}
};
}
- 跳转到修改密码界面。
OpenAccountUIService openAccountUIService = (OpenAccountUIService) OpenAccountSDK.getService(OpenAccountUIService.class);
openAccountUIService.showEmailResetPassword(this, this.getEmailResetPasswordCallback());
更多UI定制参考
如果您还需定制更多的UI,例如修改更多原生元素,您可以根据以下内容来自行实现。
- 修改更多组件的样式
账号及用户SDK开放了所有组件的样式,在SDK的deali_sdk_openaccount_styles.xml里定义了可以直接覆盖的所有样式。您可以继承对应的style再修改AndroidManifest.xml中activity的配置。详细操作请参见本文档中修改登录和注册按钮的颜色来实现。
- 修改OA界面布局
控件或Activity通过LayoutMapping类来加载layout文件。建议您不要修改现有控件的ID,直接新增控件来加载自定义的layout文件。
com.alibaba.sdk.android.openaccount.ui.LayoutMapping.put(控件(或activity).class,R.layout.xxx);
您可以在下图所示目录下查找所需的layout文件。

- 定制OA模块界面
如果您需要自定义整个界面,建议您集成原先界面的activity后,再替换SDK中整个界面的内容。您可以参照以下示例代码来实现。
//以登录界面为例
//1.继承LoginActivity,重写登录界面为OALoginActivity
public class OALoginActivity extends LoginActivity{}
//2.在 OALoginActivity中重写getLayoutName方法,将布局文件的名称返回
@Override
protected String getLayoutName() {
//替换成自己的布局文件名称
return "ali_sdk_openaccount_login2";
}
//3.在账号及用户SDK初始化后,将登录界面替换到SDK中
OALoginAdapter adapter = (OALoginAdapter) LoginBusiness.getLoginAdapter();
adapter.setDefaultLoginClass(OALoginActivity.class);
说明 在重写界面时,需将原界面中的控件全部添加上,且保持ID不变。不需用的控件隐藏处理,请勿删除,否则可能出现找不到控件的错误。
如果您还需定制除原生元素以外的内容,可以参考以下信息来实现。