简易权限界面实现

64 阅读3分钟

权限界面实现原理

1. 数据来源:PackageManager

Android 系统的PackageManager负责管理所有安装的应用信息,包括权限数据。每个应用的AndroidManifest.xml中声明的权限信息会被系统解析并存储。

关键数据结构

  • PackageInfo:包含应用的所有信息,如版本、图标、权限等

  • PermissionInfo:单个权限的详细信息

  • PermissionGroupInfo:权限组信息

获取应用权限的代码示例

java

PackageManager pm = getPackageManager();
try {
    // 获取指定应用的PackageInfo,包含权限信息
    PackageInfo packageInfo = pm.getPackageInfo(
        "com.example.app",  // 应用包名
        PackageManager.GET_PERMISSIONS  // 标志:获取权限信息
    );
    
    // 获取应用声明的所有权限
    String[] requestedPermissions = packageInfo.requestedPermissions;
    
    if (requestedPermissions != null) {
        for (String permission : requestedPermissions) {
            try {
                // 获取权限详细信息
                PermissionInfo permissionInfo = pm.getPermissionInfo(permission, 0);
                
                // 获取权限所属的组
                PermissionGroupInfo groupInfo = pm.getPermissionGroupInfo(
                    permissionInfo.group, 
                    0
                );
                
                Log.d("Permission", "权限: " + permissionInfo.loadLabel(pm));
                Log.d("Permission", "组: " + groupInfo.loadLabel(pm));
                Log.d("Permission", "描述: " + permissionInfo.loadDescription(pm));
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
    }
} catch (PackageManager.NameNotFoundException e) {
    e.printStackTrace();
}

2. 权限组的定义

Android 系统预定义了多个权限组,每个权限组包含若干相关权限。这些定义在系统源码中(frameworks/base/core/res/res/values/permission_groups.xml)。

常见权限组示例

xml

<!-- 位置权限组 -->
<permission-group name="android.permission-group.LOCATION" 
                  label="@string/permgroup_location" 
                  description="@string/permgroup_location_desc" 
                  icon="@mipmap/ic_perm_group_location" />

<!-- 包含在位置组中的权限 -->
<permission name="android.permission.ACCESS_FINE_LOCATION" 
            label="@string/permlab_accessFineLocation" 
            description="@string/permdesc_accessFineLocation" 
            protectionLevel="dangerous"
            group="android.permission-group.LOCATION" />
            
<permission name="android.permission.ACCESS_COARSE_LOCATION" 
            label="@string/permlab_accessCoarseLocation" 
            description="@string/permdesc_accessCoarseLocation" 
            protectionLevel="dangerous"
            group="android.permission-group.LOCATION" />

3. 界面实现:RecyclerView + 分组展示

系统设置中的权限界面通常使用RecyclerView实现,通过自定义Adapter将权限按组分类展示。

关键实现步骤

  1. 数据分组:将获取的权限按组 ID 分类

  2. 视图类型:定义两种视图(组标题、权限项)

  3. 展开 / 折叠:实现组的展开 / 折叠功能

简化的 Adapter 代码示例

java

public class PermissionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private static final int TYPE_GROUP = 0;
    private static final int TYPE_PERMISSION = 1;
    
    private List<Object> items = new ArrayList<>();  // 混合存储组和权限
    private Context context;
    private PackageManager pm;

    public PermissionAdapter(Context context, PackageManager pm) {
        this.context = context;
        this.pm = pm;
    }

    // 设置数据并按组分类
    public void setData(List<PermissionInfo> permissions) {
        // 使用Map按组ID分组
        Map<String, List<PermissionInfo>> groupMap = new HashMap<>();
        
        for (PermissionInfo permission : permissions) {
            String group = permission.group != null ? permission.group : "";
            groupMap.computeIfAbsent(group, k -> new ArrayList<>()).add(permission);
        }
        
        // 转换为有序列表(组标题 + 权限项)
        items.clear();
        for (Map.Entry<String, List<PermissionInfo>> entry : groupMap.entrySet()) {
            try {
                // 获取组信息
                PermissionGroupInfo groupInfo = pm.getPermissionGroupInfo(entry.getKey(), 0);
                items.add(groupInfo);
                items.addAll(entry.getValue());
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        
        notifyDataSetChanged();
    }

    @Override
    public int getItemViewType(int position) {
        return items.get(position) instanceof PermissionGroupInfo ? TYPE_GROUP : TYPE_PERMISSION;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        // 创建不同类型的ViewHolder(组标题和权限项)
        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
        if (viewType == TYPE_GROUP) {
            View view = inflater.inflate(R.layout.item_permission_group, parent, false);
            return new GroupViewHolder(view);
        } else {
            View view = inflater.inflate(R.layout.item_permission, parent, false);
            return new PermissionViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        // 绑定数据到ViewHolder
        if (holder instanceof GroupViewHolder) {
            GroupViewHolder groupHolder = (GroupViewHolder) holder;
            PermissionGroupInfo groupInfo = (PermissionGroupInfo) items.get(position);
            groupHolder.bind(groupInfo);
        } else {
            PermissionViewHolder permissionHolder = (PermissionViewHolder) holder;
            PermissionInfo permissionInfo = (PermissionInfo) items.get(position);
            permissionHolder.bind(permissionInfo);
        }
    }

    @Override
    public int getItemCount() {
        return items.size();
    }
    
    // ViewHolder实现省略...
}

权限状态的获取

除了权限定义信息,界面还需要显示权限的当前状态(已授予 / 拒绝)。这需要通过PackageManager查询:

java

// 检查权限状态
int permissionState = pm.checkPermission(
    "android.permission.CAMERA",  // 权限名称
    "com.example.app"             // 应用包名
);

if (permissionState == PackageManager.PERMISSION_GRANTED) {
    // 权限已授予
} else {
    // 权限被拒绝
}

总结

组件故事类比技术实现
PackageManager餐厅许可证数据库获取应用权限信息
权限组许可证分类展示墙系统预定义的权限分组
RecyclerView菜单展示系统实现权限列表的分组展示
权限状态许可证的当前有效性通过 checkPermission 查询权限状态

通过这种方式,Android 系统将应用权限信息组织成用户友好的界面,让用户可以清晰地了解每个应用的权限请求和使用情况