# Android 系统应用开发全面讲解
## 一、Android 系统应用概述
### 1.1 系统应用特点
- **系统签名**:使用platform签名
- **特殊权限**:可以获取系统级权限
- **预装应用**:随ROM一起发布
- **核心功能**:提供系统基础服务
### 1.2 开发环境配置
```bash
# 下载AOSP源码
repo init -u https://android.googlesource.com/platform/manifest
repo sync
# 编译环境
source build/envsetup.sh
lunch aosp_x86_64-eng
make -j8
```
## 二、主题应用开发
### 2.1 主题框架架构
```java
// 主题管理器
public class ThemeManager {
private static final String THEME_PATH = "/data/themes/";
private Context mContext;
private ThemeInfo mCurrentTheme;
public void applyTheme(String themeId) {
// 加载主题资源
Resources themeResources = loadThemeResources(themeId);
// 应用主题
updateSystemUI(themeResources);
updateLauncher(themeResources);
updateApps(themeResources);
}
private Resources loadThemeResources(String themeId) {
try {
AssetManager assetManager = AssetManager.class.newInstance();
Method addAssetPath = AssetManager.class.getMethod(
"addAssetPath", String.class);
addAssetPath.invoke(assetManager, THEME_PATH + themeId);
Resources superRes = mContext.getResources();
return new Resources(assetManager,
superRes.getDisplayMetrics(),
superRes.getConfiguration());
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
```
### 2.2 主题资源结构
```xml
<!-- theme_config.xml -->
<theme>
<info>
<name>Material Dark</name>
<author>System</author>
<version>1.0</version>
</info>
<colors>
<color name="primary">#212121</color>
<color name="primary_dark">#000000</color>
<color name="accent">#448AFF</color>
</colors>
<wallpapers>
<wallpaper src="wallpaper_home.jpg" />
<wallpaper src="wallpaper_lock.jpg" />
</wallpapers>
<icons>
<icon package="com.android.settings"
drawable="ic_settings_themed" />
</icons>
</theme>
```
### 2.3 动态主题切换
```java
public class ThemeService extends Service {
private static final String ACTION_THEME_CHANGED =
"android.intent.action.THEME_CHANGED";
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
if (ACTION_THEME_CHANGED.equals(action)) {
String themeId = intent.getStringExtra("theme_id");
applyThemeChange(themeId);
}
return START_STICKY;
}
private void applyThemeChange(String themeId) {
// 更新配置
Configuration config = new Configuration();
config.uiMode = Configuration.UI_MODE_NIGHT_YES;
// 通知系统UI更新
Intent broadcast = new Intent("com.android.systemui.THEME_CHANGED");
broadcast.putExtra("theme_id", themeId);
sendBroadcast(broadcast);
// 重启相关进程
ActivityManager am = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
am.killBackgroundProcesses("com.android.systemui");
}
}
```
## 三、设置应用开发
### 3.1 Settings Provider
```java
// 自定义设置项
public class CustomSettings {
public static final String AUTHORITY = "com.android.settings.custom";
// 设置键值
public static final class System {
public static final String DISPLAY_BRIGHTNESS_MODE = "display_brightness_mode";
public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse";
public static final String BATTERY_PERCENTAGE = "battery_percentage";
}
// 获取设置值
public static int getInt(ContentResolver resolver, String name, int def) {
String value = Settings.System.getString(resolver, name);
try {
return value != null ? Integer.parseInt(value) : def;
} catch (NumberFormatException e) {
return def;
}
}
// 设置值
public static boolean putInt(ContentResolver resolver, String name, int value) {
return Settings.System.putString(resolver, name, Integer.toString(value));
}
}
```
### 3.2 设置界面开发
```java
// 自定义设置Fragment
public class DisplaySettingsFragment extends PreferenceFragmentCompat {
private static final String KEY_BRIGHTNESS = "brightness";
private static final String KEY_ADAPTIVE_BRIGHTNESS = "adaptive_brightness";
private static final String KEY_SLEEP_TIMEOUT = "sleep_timeout";
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
setPreferencesFromResource(R.xml.display_settings, rootKey);
// 亮度设置
SeekBarPreference brightness = findPreference(KEY_BRIGHTNESS);
brightness.setMax(255);
brightness.setValue(getBrightness());
brightness.setOnPreferenceChangeListener((preference, newValue) -> {
setBrightness((int) newValue);
return true;
});
// 自适应亮度
SwitchPreference adaptiveBrightness = findPreference(KEY_ADAPTIVE_BRIGHTNESS);
adaptiveBrightness.setChecked(isAdaptiveBrightnessEnabled());
adaptiveBrightness.setOnPreferenceChangeListener((preference, newValue) -> {
setAdaptiveBrightness((boolean) newValue);
return true;
});
}
private int getBrightness() {
try {
return Settings.System.getInt(getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS);
} catch (Settings.SettingNotFoundException e) {
return 128;
}
}
private void setBrightness(int brightness) {
Settings.System.putInt(getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, brightness);
// 立即应用亮度
WindowManager.LayoutParams params = getActivity().getWindow().getAttributes();
params.screenBrightness = brightness / 255.0f;
getActivity().getWindow().setAttributes(params);
}
}
```
### 3.3 系统设置监听
```java
public class SettingsObserver extends ContentObserver {
private Context mContext;
private OnSettingsChangedListener mListener;
public interface OnSettingsChangedListener {
void onBrightnessChanged(int brightness);
void onVolumeChanged(int volume);
void onWifiStateChanged(boolean enabled);
}
public SettingsObserver(Context context, Handler handler) {
super(handler);
mContext = context;
}
public void register() {
ContentResolver resolver = mContext.getContentResolver();
// 监听亮度变化
resolver.registerContentObserver(
Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS),
false, this);
// 监听音量变化
resolver.registerContentObserver(
Settings.System.getUriFor(Settings.System.VOLUME_RING),
false, this);
// 监听WiFi状态
resolver.registerContentObserver(
Settings.Global.getUriFor(Settings.Global.WIFI_ON),
false, this);
}
@Override
public void onChange(boolean selfChange, Uri uri) {
if (mListener == null) return;
if (uri.equals(Settings.System.getUriFor(Settings.System.SCREEN_BRIGHTNESS))) {
int brightness = Settings.System.getInt(mContext.getContentResolver(),
Settings.System.SCREEN_BRIGHTNESS, 128);
mListener.onBrightnessChanged(brightness);
}
}
}
```
## 四、相册应用开发
### 4.1 相册架构设计
```java
// 图片数据模型
public class PhotoItem {
private long id;
private String path;
private String name;
private long dateModified;
private long size;
private int width;
private int height;
private String mimeType;
private float latitude;
private float longitude;
// Getters and setters...
}
// 相册数据加载器
public class PhotoLoader {
private static final String[] PROJECTION = {
MediaStore.Images.Media._ID,
MediaStore.Images.Media.DATA,
MediaStore.Images.Media.DISPLAY_NAME,
MediaStore.Images.Media.DATE_MODIFIED,
MediaStore.Images.Media.SIZE,
MediaStore.Images.Media.WIDTH,
MediaStore.Images.Media.HEIGHT,
MediaStore.Images.Media.MIME_TYPE
};
public List<PhotoItem> loadPhotos(Context context) {
List<PhotoItem> photos = new ArrayList<>();
ContentResolver resolver = context.getContentResolver();
Cursor cursor = resolver.query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
PROJECTION,
null,
null,
MediaStore.Images.Media.DATE_MODIFIED + " DESC"
);
if (cursor != null) {
while (cursor.moveToNext()) {
PhotoItem photo = new PhotoItem();
photo.setId(cursor.getLong(0));
photo.setPath(cursor.getString(1));
photo.setName(cursor.getString(2));
photo.setDateModified(cursor.getLong(3));
photo.setSize(cursor.getLong(4));
photo.setWidth(cursor.getInt(5));
photo.setHeight(cursor.getInt(6));
photo.setMimeType(cursor.getString(7));
photos.add(photo);
}
cursor.close();
}
return photos;
}
}
```
### 4.2 图片浏览实现
```java
// 图片查看器
public class PhotoViewerActivity extends AppCompatActivity {
private ViewPager2 viewPager;
private List<PhotoItem> photos;
private int currentPosition;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_photo_viewer);
viewPager = findViewById(R.id.view_pager);
photos = getIntent().getParcelableArrayListExtra("photos");
currentPosition = getIntent().getIntExtra("position", 0);
PhotoPagerAdapter adapter = new PhotoPagerAdapter(photos);
viewPager.setAdapter(adapter);
viewPager.setCurrentItem(currentPosition, false);
// 添加页面切换监听
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
updateUI(position);
}
});
}
// ViewPager适配器
private class PhotoPagerAdapter extends RecyclerView.Adapter<PhotoViewHolder> {
private List<PhotoItem> photos;
public PhotoPagerAdapter(List<PhotoItem> photos) {
this.photos = photos;
}
@NonNull
@Override
public PhotoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_photo_view, parent, false);
return new PhotoViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PhotoViewHolder holder, int position) {
PhotoItem photo = photos.get(position);
// 使用Glide加载图片
Glide.with(holder.itemView.getContext())
.load(photo.getPath())
.fitCenter()
.into(holder.photoView);
// 支持手势缩放
holder.photoView.setOnPhotoTapListener((view, x, y) -> {
toggleSystemUI();
});
}
@Override
public int getItemCount() {
return photos.size();
}
}
}
```
### 4.3 相册功能实现
```java
// 相册管理器
public class AlbumManager {
private Context mContext;
private ContentResolver mResolver;
// 创建相册
public boolean createAlbum(String albumName) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.RELATIVE_PATH,
Environment.DIRECTORY_PICTURES + "/" + albumName);
Uri uri = mResolver.insert(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
return uri != null;
}
// 移动图片到相册
public boolean moveToAlbum(PhotoItem photo, String albumName) {
try {
File sourceFile = new File(photo.getPath());
File destDir = new File(Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES), albumName);
if (!destDir.exists()) {
destDir.mkdirs();
}
File destFile = new File(destDir, photo.getName());
// 复制文件
FileUtils.copy(sourceFile, destFile);
// 更新媒体库
MediaScannerConnection.scanFile(mContext,
new String[]{destFile.getAbsolutePath()},
null, null);
// 删除原文件
deletePhoto(photo);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
// 删除图片
public boolean deletePhoto(PhotoItem photo) {
int rows = mResolver.delete(
ContentUris.withAppendedId(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI, photo.getId()),
null, null);
return rows > 0;
}
// 图片编辑
public void editPhoto(PhotoItem photo) {
Intent intent = new Intent(Intent.ACTION_EDIT);
intent.setDataAndType(Uri.parse(photo.getPath()), photo.getMimeType());
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
mContext.startActivity(intent);
}
}
```
### 4.4 图片处理功能
```java
// 图片处理工具类
public class PhotoProcessor {
// 压缩图片
public static Bitmap compressImage(String imagePath, int targetWidth, int targetHeight) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(imagePath, options);
// 计算缩放比例
int inSampleSize = calculateInSampleSize(options, targetWidth, targetHeight);
options.inJustDecodeBounds = false;
options.inSampleSize = inSampleSize;
return BitmapFactory.decodeFile(imagePath, options);
}
// 旋转图片
public static Bitmap rotateImage(Bitmap source, float angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(source, 0, 0,
source.getWidth(), source.getHeight(), matrix, true);
}
// 裁剪图片
public static Bitmap cropImage(Bitmap source, Rect cropRect) {
return Bitmap.createBitmap(source,
cropRect.left, cropRect.top,
cropRect.width(), cropRect.height());
}
// 添加滤镜
public static Bitmap applyFilter(Bitmap source, ColorMatrix colorMatrix) {
Bitmap result = Bitmap.createBitmap(
source.getWidth(), source.getHeight(), source.getConfig());
Canvas canvas = new Canvas(result);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
canvas.drawBitmap(source, 0, 0, paint);
return result;
}
// 保存编辑后的图片
public static boolean saveImage(Bitmap bitmap, String outputPath, int quality) {
try {
FileOutputStream out = new FileOutputStream(outputPath);
bitmap.compress(Bitmap.CompressFormat.JPEG, quality, out);
out.flush();
out.close();
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
```
## 五、系统权限和安全
### 5.1 系统签名配置
```xml
<!-- AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.gallery"
android:sharedUserId="android.uid.system">
<!-- 系统权限 -->
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
<application
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:persistent="true"
android:allowBackup="false">
<!-- 声明为系统应用 -->
<meta-data
android:name="android.app.system"
android:value="true" />
</application>
</manifest>
```
### 5.2 SELinux配置
```bash
# file_contexts
/system/priv-app/Gallery(/.*)? u:object_r:system_app_data_file:s0
/data/data/com.android.gallery(/.*)? u:object_r:system_app_data_file:s0
# gallery.te
type gallery_app, domain;
app_domain(gallery_app)
# 允许访问媒体文件
allow gallery_app media_rw_data_file:dir rw_dir_perms;
allow gallery_app media_rw_data_file:file rw_file_perms;
# 允许访问系统设置
allow gallery_app system_app_data_file:dir rw_dir_perms;
allow gallery_app system_app_data_file:file rw_file_perms;
```
## 六、性能优化
### 6.1 图片加载优化
```java
public class ImageLoader {
private LruCache<String, Bitmap> mMemoryCache;
private DiskLruCache mDiskCache;
private ExecutorService mExecutor;
public ImageLoader(Context context) {
// 内存缓存
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount() / 1024;
}
};
// 磁盘缓存
File cacheDir = context.getCacheDir();
mDiskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024);
// 线程池
mExecutor = Executors.newFixedThreadPool(4);
}
public void loadImage(String url, ImageView imageView) {
// 先从内存缓存获取
Bitmap bitmap = mMemoryCache.get(url);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
return;
}
// 异步加载
mExecutor.execute(() -> {
try {
// 从磁盘缓存获取
bitmap = getBitmapFromDiskCache(url);
if (bitmap == null) {
// 从网络或本地加载
bitmap = downloadBitmap(url);
if (bitmap != null) {
addBitmapToCache(url, bitmap);
}
}
// 更新UI
if (bitmap != null) {
runOnUiThread(() -> imageView.setImageBitmap(bitmap));
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
```
### 6.2 内存管理
```java
public class MemoryManager {
private static final int LOW_MEMORY_THRESHOLD = 50 * 1024 * 1024; // 50MB
public static void checkMemory(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ActivityManager.MemoryInfo memInfo = new ActivityManager.MemoryInfo();
am.getMemoryInfo(memInfo);
if (memInfo.availMem < LOW_MEMORY_THRESHOLD) {
// 清理缓存
clearCache();
// 触发GC
System.gc();
// 降低图片质量
reduceImageQuality();
}
}
private static void clearCache() {
// 清理图片缓存
ImageLoader.getInstance().clearMemoryCache();
// 清理临时文件
FileUtils.deleteDirectory(new File(getCacheDir(), "temp"));
}
}
```
## 七、最佳实践建议
### 7.1 开发规范
1. **代码规范**
- 遵循AOSP代码风格
- 使用Android官方架构组件
- 注重代码可维护性
2. **性能优化**
- 合理使用缓存机制
- 避免主线程阻塞
- 及时释放资源
3. **安全考虑**
- 严格权限控制
- 数据加密存储
- 防止信息泄露
### 7.2 测试策略
```java
// 单元测试示例
@RunWith(AndroidJUnit4.class)
public class PhotoLoaderTest {
@Test
public void testLoadPhotos() {
Context context = ApplicationProvider.getApplicationContext();
PhotoLoader loader = new PhotoLoader();
List<PhotoItem> photos = loader.loadPhotos(context);
assertNotNull(photos);
assertTrue(photos.size() > 0);
}
@Test
public void testImageCompression() {
Bitmap original = BitmapFactory.decodeResource(
getResources(), R.drawable.test_image);
Bitmap compressed = PhotoProcessor.compressImage(
original, 800, 600);
assertTrue(compressed.getWidth() <= 800);
assertTrue(compressed.getHeight() <= 600);
}
}
```
这个全面的讲解涵盖了Android系统应用开发的主要方面,包括主题、设置和相册应用的具体实现。在实际开发中,还需要根据具体需求进行调整和优化。