You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中如何以扁平列表展示已安装应用(含图标与名称)

React Native 获取已安装应用列表并高效展示

要实现这个需求,核心分为原生模块获取应用数据和RN端用FlatList高效渲染两部分,以下是具体实现:


一、原生模块实现(重点在Android,iOS有沙盒限制)

Android 端实现

RN本身没有提供获取已安装应用的API,需要自定义原生模块:

  1. 创建AppListModule.java(放在项目android/app/src/main/java/com/[你的包名]/目录下):
package com.yourappname;

import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Base64;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;

import java.io.ByteArrayOutputStream;
import java.util.List;

public class AppListModule extends ReactContextBaseJavaModule {

    public AppListModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "AppListModule"; // RN端调用的模块名称
    }

    @ReactMethod
    public void getInstalledApps(Callback callback) {
        PackageManager pm = getReactApplicationContext().getPackageManager();
        List<ApplicationInfo> apps = pm.getInstalledApplications(PackageManager.GET_META_DATA);
        WritableArray appList = new WritableNativeArray();

        for (ApplicationInfo app : apps) {
            // 可选:过滤系统应用,只保留用户自行安装的应用
            if ((app.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
                WritableMap appMap = new WritableNativeMap();
                appMap.putString("name", pm.getApplicationLabel(app).toString());
                appMap.putString("packageName", app.packageName);
                
                // 将应用图标转为Base64格式,供RN端直接加载
                Drawable icon = pm.getApplicationIcon(app);
                Bitmap bitmap = ((BitmapDrawable) icon).getBitmap();
                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                bitmap.compress(Bitmap.CompressFormat.PNG, 80, stream); // 压缩图标质量,减少数据体积
                byte[] byteArray = stream.toByteArray();
                appMap.putString("iconBase64", Base64.encodeToString(byteArray, Base64.DEFAULT));
                
                appList.pushMap(appMap);
            }
        }
        callback.invoke(null, appList);
    }
}
  1. 创建包注册类AppListPackage.java:
package com.yourappname;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class AppListPackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new AppListModule(reactContext));
        return modules;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}
  1. 在MainApplication.java中注册这个包:
@Override
protected List<ReactPackage> getPackages() {
    List<ReactPackage> packages = new PackageList(this).getPackages();
    packages.add(new AppListPackage()); // 添加自定义包
    return packages;
}

iOS 端说明

iOS受沙盒机制限制,无法通过公开API获取所有已安装应用的列表。使用私有API(如LSApplicationWorkspace)虽然能拿到数据,但上线会被App Store拒绝。如果仅需检测特定应用,可使用canOpenURL方法,但无法实现遍历全部应用的需求。


二、RN 端实现

1. 封装原生模块调用

创建AppListHelper.js,统一封装原生模块调用逻辑:

import { NativeModules } from 'react-native';

export const getInstalledApps = () => {
  return new Promise((resolve, reject) => {
    NativeModules.AppListModule.getInstalledApps((err, apps) => {
      if (err) reject(err);
      else resolve(apps);
    });
  });
};

2. 用FlatList高效展示应用列表

主组件示例代码:

import React, { useState, useEffect } from 'react';
import { View, FlatList, Image, Text, StyleSheet, ActivityIndicator } from 'react-native';
import { getInstalledApps } from './AppListHelper';

export default function AppListScreen() {
  const [appList, setAppList] = useState([]);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    loadAppList();
  }, []);

  const loadAppList = async () => {
    try {
      const apps = await getInstalledApps();
      setAppList(apps);
    } catch (err) {
      console.error('加载应用列表失败:', err);
    } finally {
      setIsLoading(false);
    }
  };

  const renderAppItem = ({ item }) => (
    <View style={styles.itemRow}>
      <Image
        style={styles.appIcon}
        source={{ uri: `data:image/png;base64,${item.iconBase64}` }}
        resizeMode="contain"
      />
      <Text style={styles.appName}>{item.name}</Text>
    </View>
  );

  if (isLoading) {
    return (
      <View style={styles.loadingContainer}>
        <ActivityIndicator size="large" />
      </View>
    );
  }

  return (
    <FlatList
      data={appList}
      keyExtractor={(item) => item.packageName} // 用包名作为唯一key,避免不必要的重渲染
      renderItem={renderAppItem}
      initialNumToRender={10} // 初始渲染10个列表项,保证首屏快速加载
      maxToRenderPerBatch={5} // 每批次渲染5个,平衡流畅度与性能
      windowSize={5} // 可视区域外预渲染5个,提升滚动流畅度
      removeClippedSubviews={true} // 移除屏幕外视图,节省内存
      contentContainerStyle={styles.listContainer}
    />
  );
}

const styles = StyleSheet.create({
  loadingContainer: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  listContainer: {
    paddingVertical: 8,
  },
  itemRow: {
    flexDirection: 'row',
    alignItems: 'center',
    paddingHorizontal: 16,
    paddingVertical: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#f0f0f0',
  },
  appIcon: {
    width: 40,
    height: 40,
    marginRight: 12,
  },
  appName: {
    fontSize: 16,
    flex: 1,
    color: '#333',
  },
});

三、性能优化与最佳实践

  1. FlatList 优化:
    • 必须通过keyExtractor提供唯一标识,让RN精准识别列表项变化,避免无效重渲染
    • 根据设备性能调整initialNumToRender、maxToRenderPerBatch、windowSize参数,优先保证首屏加载速度
    • 开启removeClippedSubviews,Android默认开启,iOS需手动设置,可大幅降低内存占用
  2. 原生端优化:
    • 压缩图标质量,减少Base64数据体积,避免阻塞JS线程
    • 按需过滤系统应用,减少返回的数据量
    • 若应用数量极多,可考虑在原生端生成临时图标文件,RN端通过文件URI加载,比Base64更节省内存
  3. 用户体验优化:
    • 显示加载状态,避免空白屏
    • 捕获并处理异常,给用户友好的错误提示

内容的提问来源于stack exchange,提问作者Munawar Manzoor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 23:10:43