小程序的某些特殊 API,如定位、相机、相册等,通常会提示用户授权,待用户允许后方可执行API。
小程序容器允许针对 API 调用进行如下扩展:
自定义文案提示,接入方可控制文案以及展示样式。
允许接入方读写权限配置。
此扩展配置仅在后台已开启 小程序权限控制 时才可用。
权限配置
对于需要用户授权使用的 API,都必须配置一个权限 key。多个 API 可对应同一个 key,比如选择图片和扫码可对应一个相机的 key。
小程序已有默认配置的 key 以及对应的 API,详见下表:
权限 | key | API |
---|---|---|
相机 | camera | scan, chooseImage, chooseVideo |
相册 | album | saveImage, saveVideosToPhotosAlbum, shareTokenImageSilent |
位置 | location | getLocation, getCurrentLocation |
容器读取接入方传入的如下权限配置类来处理 API 调用权限:
public static class PermissionConfig {
public String action; // API 名称
public String key; // 权限 key
public String desc; // API 调用展示的文案,文案中可加入 %s 占位符,容器会自动填入小程序的名称
public PermissionConfig() {
}
}
当 action
为 chooseImage
、chooseVideo
时,接入方配置的 key 是不生效的,容器有特殊逻辑处理这两个 API,但文案依然是可配置的。
加载配置
加载权限配置,需使用容器提供的 TinyAppPermissionExternProvider
接口。接口类如下:
package com.alipay.mobile.nebula.provider;
import android.content.Context;
import java.util.List;
public abstract class TinyAppPermissionExternProvider {
public interface PermissionCheckCallback {
void accept();
void deny();
}
public abstract List<PermissionConfig> loadPermissionCheckConfig();
public abstract void showPermissionDialog(Context context, String appId, PermissionConfig config, PermissionCheckCallback callback);
public abstract boolean shouldHandlePermissionDialog();
}
loadPermissionCheckConfig
方法负责将权限配置加载至容器。
自定义展示
自定义展示授权信息并允许用户进行操作确认。
首先需使
shouldHandlePermissionDialog
方法返回true
。随后容器会调用
showPermissionDialog
方法,接入方可在此处展示自定义样式。当用户接受或者拒绝调用,需要调用
PermissionCheckCallback
接口的相应方法。
代码示例如下:
package com.mpaas.demo.nebula;
import android.content.Context;
import com.alipay.mobile.antui.dialog.AUNoticeDialog;
import com.alipay.mobile.nebula.provider.TinyAppPermissionExternProvider;
import java.util.ArrayList;
import java.util.List;
public class TinyExternalPermissionCheckProvider extends TinyAppPermissionExternProvider {
private PermissionConfig create(String action, String key, String desc) {
PermissionConfig config = new PermissionConfig();
config.action = action;
config.key = key;
config.desc = desc;
return config;
}
private List<PermissionConfig> permissionConfigs = new ArrayList<>();
public TinyExternalPermissionCheckProvider() {
permissionConfigs.add(create("saveFile", "file", "%s想使用您的文件存储"));
permissionConfigs.add(create("getFileInfo", "file", "%s想使用您的文件存储"));
}
@Override
public List<PermissionConfig> loadPermissionCheckConfig() {
return permissionConfigs;
}
@Override
public void showPermissionDialog(Context context, String action, PermissionConfig permissionConfig, final PermissionCheckCallback permissionCheckCallback) {
AUNoticeDialog dialog = new AUNoticeDialog(context, "授权提醒", permissionConfig.desc, "接受", "拒绝");
dialog.setPositiveListener(new AUNoticeDialog.OnClickPositiveListener() {
@Override
public void onClick() {
permissionCheckCallback.accept();
}
});
dialog.setNegativeListener(new AUNoticeDialog.OnClickNegativeListener() {
@Override
public void onClick() {
permissionCheckCallback.deny();
}
});
dialog.show();
}
@Override
public boolean shouldHandlePermissionDialog() {
return true;
}
}
读写配置
读取配置可调用如下方法:
MPTinyHelper.getInstance().getMiniProgramSetting(appId)
小程序配置是以应用和用户两个维度存储的,因此要确保应用已经调用
MPLogger.setUserId
方法。当 API 从未被调用的情况下,是获取不到该 API 对应的 key 值的授权状态的。
写入配置可调用如下方法:
MPTinyHelper.getInstance().updateMiniProgramSetting(appId, key, isAllowed);
代码示例如下:
package com.mpaas.demo.nebula;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import com.alipay.mobile.antui.basic.AUSearchBar;
import com.alipay.mobile.antui.tablelist.AUSwitchListItem;
import com.alipay.mobile.framework.app.ui.BaseFragmentActivity;
import com.alipay.mobile.nebula.util.H5Utils;
import com.mpaas.nebula.adapter.api.MPTinyHelper;
import java.util.Map;
public class PermissionDisplayActivity extends BaseFragmentActivity {
private ViewGroup mScrollView;
private AUSearchBar mSearchInputBox;
private Map<String, Boolean> permissions;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_permission);
mScrollView = (ViewGroup) findViewById(R.id.scrollview);
mSearchInputBox = (AUSearchBar) findViewById(R.id.search);
mSearchInputBox.getSearchButton().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mScrollView.removeAllViews();
final String appId = mSearchInputBox.getSearchEditView().getText().toString();
permissions = MPTinyHelper.getInstance().getMiniProgramSetting(appId);
for (Map.Entry<String, Boolean> entry : permissions.entrySet()) {
AUSwitchListItem item = new AUSwitchListItem(PermissionDisplayActivity.this);
final String key = entry.getKey();
item.setLeftText(key);
item.getCompoundSwitch().setChecked(entry.getValue());
item.getCompoundSwitch().setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
MPTinyHelper.getInstance().updateMiniProgramSetting(appId, key, isChecked);
}
});
mScrollView.addView(item, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, H5Utils.dip2px(PermissionDisplayActivity.this, 48)));
}
}
});
}
}