Android
快来分享你的内容吧~
2024-12-04·产品经理- 做一个App,可以兼容主流android手机,主流的一些Android 版本呢,需要考虑什么?应该学习什么?一、问题:您好,做一个App,可以兼容主流android手机,主流的一些Android 版本呢,需要考虑什么?应该学习什么?二、背景我现在开发的App,基本上是定好在一个固定的Android版本、Android机、固定的内存,所以我只需要考虑这一个即可。但如果我面对的不是不同的版本,我应该考虑什么,应该学习什么?想请教一下这个问题。...查看全文程序员鱼皮:在开发 APP 上,我的专业性有限,所以帮你多查阅了一些资料。这个问题总结为 “如何开发兼容性好的 Android APP”下次遇到这种问题,第一时间你要想到从源头去找解决方案。Android 的源头是哪里?那肯定是 Google 的官方文档对不对?没错,从官方文档中,我们就能看到一些 Android 兼容性的介绍和最佳实践:- https://developer.android.google.c

- 大三安卓客户端准备找实习求助求职目标希望成为一名安卓客户端开发人员,想拿到一个中大厂的实习offer个人情况26毕业河北师范大学本科,想在明年一月份开始投简历面试,有过一年acm经历,算法基础还可以目前javase没有什么问题,javaee和sping等后端框架学校正在学习中,安卓的技术栈学习了安卓的四大组件,布局的相关内容,常见的一些框架比如okhttp,glide也学完了数据库相关的mysql和安卓的sqlite学完暂时...查看全文拭心shixin:来了来了,安卓学习路线看这篇文章哈:https://www.codefather.cn/course/1789189862986850306/section/1789190210308775938?type= 你现在安卓的基础知识学了一些,但距离胜任工作还有一些需要掌握的,比如自定义 View、Gradle 构建、性能优化、Kotlin等等(太新的技术暂时不建议学,比如 Compose),接下来

Android 自定义系统服务初始化流程详解
# Android 自定义系统服务初始化流程详解 ## 1. 概述 自定义系统服务的初始化是一个系统化的过程,涉及多个组件和阶段的协同工作。下面是完整的初始化流程图和详细说明: ```mermaid flowchart TD A[定义AIDL接口] --> B[实现服务Stub] B --> C[创建SystemService] C --> D[在SystemServer中注册] D --> E[Context中添加常量] E --> F[权限配置] F --> G[SELinux策略] G --> H[构建配置] H --> I[系统启动时初始化] I --> J[启动阶段回调] J --> K[服务就绪] ``` ## 2. 详细初始化流程 ### 2.1 定义服务接口 (AIDL) 首先创建AIDL接口文件,这是定义服务契约的基础: ```java // frameworks/base/core/java/android/os/ICustomService.aidl package android.os; import android.annotation.Nullable; import android.annotation.NonNull; /** * @hide Custom service interface for advanced system operations */ interface ICustomService { // 示例方法:设置配置值 boolean setConfiguration(in String key, in String value); // 示例方法:获取配置值 String getConfiguration(in String key); // 示例方法:执行特定操作 int performOperation(in int operationId); } ``` ### 2.2 实现服务核心逻辑 创建服务的具体实现,继承自Stub类: ```java // frameworks/base/services/core/java/com/android/server/CustomService.java package com.android.server; import android.content.Context; import android.os.ICustomService; import android.util.Slog; import android.util.ArrayMap; import java.util.Map; public class CustomService extends ICustomService.Stub { private static final String TAG = "CustomService"; private final Context mContext; private final Map<String, String> mConfigurations = new ArrayMap<>(); // 单例实例 private static CustomService sInstance; public CustomService(Context context) { mContext = context; sInstance = this; Slog.i(TAG, "CustomService initialized"); // 初始化默认配置 initializeDefaultConfigurations(); } public static CustomService getInstance() { return sInstance; } private void initializeDefaultConfigurations() { mConfigurations.put("timeout", "5000"); mConfigurations.put("retry_count", "3"); mConfigurations.put("debug_mode", "false"); } @Override public boolean setConfiguration(String key, String value) { // 权限检查 mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_CUSTOM_SERVICE, "Requires MANAGE_CUSTOM_SERVICE permission"); if (key == null || value == null) { Slog.w(TAG, "setConfiguration: null key or value"); return false; } mConfigurations.put(key, value); Slog.d(TAG, "Configuration set: " + key + " = " + value); return true; } @Override public String getConfiguration(String key) { // 权限检查 mContext.enforceCallingOrSelfPermission( android.Manifest.permission.USE_CUSTOM_SERVICE, "Requires USE_CUSTOM_SERVICE permission"); return mConfigurations.get(key); } @Override public int performOperation(int operationId) { // 权限检查 mContext.enforceCallingOrSelfPermission( android.Manifest.permission.MANAGE_CUSTOM_SERVICE, "Requires MANAGE_CUSTOM_SERVICE permission"); Slog.i(TAG, "Performing operation: " + operationId); // 执行具体操作逻辑 switch (operationId) { case 1: return operation1(); case 2: return operation2(); default: Slog.w(TAG, "Unknown operation ID: " + operationId); return -1; } } private int operation1() { // 操作1的具体实现 return 100; } private int operation2() { // 操作2的具体实现 return 200; } // 系统启动阶段回调 public void onSystemReady() { Slog.i(TAG, "System is ready, performing final initialization"); // 系统就绪后的初始化操作 } // 启动完成回调 public void onBootCompleted() { Slog.i(TAG, "Boot completed, starting background operations"); // 启动后台任务等 } } ``` ### 2.3 创建SystemService包装器 为了更好的集成到系统服务生命周期中,创建SystemService包装器: ```java // frameworks/base/services/core/java/com/android/server/CustomSystemService.java package com.android.server; import android.content.Context; import android.util.Slog; import com.android.server.SystemService; public class CustomSystemService extends SystemService { private static final String TAG = "CustomSystemService"; private final CustomService mCustomService; public CustomSystemService(Context context) { super(context); mCustomService = new CustomService(context); Slog.i(TAG, "CustomSystemService created"); } @Override public void onStart() { Slog.i(TAG, "Publishing CustomService"); publishBinderService(Context.CUSTOM_SERVICE, mCustomService); publishLocalService(CustomService.class, mCustomService); } @Override public void onBootPhase(int phase) { Slog.d(TAG, "Boot phase: " + phase); if (phase == PHASE_SYSTEM_SERVICES_READY) { // 系统服务就绪阶段 mCustomService.onSystemReady(); } else if (phase == PHASE_BOOT_COMPLETED) { // 启动完成阶段 mCustomService.onBootCompleted(); } } @Override public void onStartUser(int userHandle) { Slog.i(TAG, "Starting for user: " + userHandle); // 用户启动时的处理 } @Override public void onUnlockUser(int userHandle) { Slog.i(TAG, "Unlocking user: " + userHandle); // 用户解锁时的处理 } @Override public void onStopUser(int userHandle) { Slog.i(TAG, "Stopping user: " + userHandle); // 用户停止时的处理 } } ``` ### 2.4 在SystemServer中注册服务 在SystemServer的适当阶段启动自定义服务: ```java // frameworks/base/services/java/com/android/server/SystemServer.java public final class SystemServer { // ... private void startBootstrapServices() { // ... 其他引导服务 // 启动自定义服务(如果需要早期启动) try { traceBeginAndSlog("StartCustomService"); mSystemServiceManager.startService(CustomSystemService.class); traceEnd(); } catch (Throwable e) { reportWtf("starting CustomService", e); } } private void startOtherServices() { // ... 其他服务 // 或者在这里启动(如果不需要早期启动) try { traceBeginAndSlog("StartCustomService"); mSystemServiceManager.startService(CustomSystemService.class); traceEnd(); } catch (Throwable e) { reportWtf("starting CustomService", e); } // ... } } ``` ### 2.5 在Context中添加服务常量 ```java // frameworks/base/core/java/android/content/Context.java public abstract class Context { // ... /** * Use with {@link #getSystemService} to retrieve a {@link android.os.ICustomService} * for managing custom system operations. * * @see #getSystemService * @hide */ public static final String CUSTOM_SERVICE = "custom_service"; // ... } ``` ### 2.6 添加权限定义 ```xml <!-- frameworks/base/core/res/AndroidManifest.xml --> <permission android:name="android.permission.MANAGE_CUSTOM_SERVICE" android:protectionLevel="signature|privileged" android:label="@string/permlab_manageCustomService" android:description="@string/permdesc_manageCustomService" /> <permission android:name="android.permission.USE_CUSTOM_SERVICE" android:protectionLevel="normal" android:label="@string/permlab_useCustomService" android:description="@string/permdesc_useCustomService" /> ``` ### 2.7 添加SELinux策略 ```selinux # device/yourvendor/yourdevice/sepolicy/common/service_contexts custom_service u:object_r:custom_service:s0 # device/yourvendor/yourdevice/sepolicy/common/service.te type custom_service, system_api_service, system_server_service, service_manager_type; # device/yourvendor/yourdevice/sepolicy/common/system_server.te allow system_server custom_service:service_manager { add find }; allow system_server custom_service:binder { call transfer }; # device/yourvendor/yourdevice/sepolicy/common/your_app.te allow your_app custom_service:service_manager find; allow your_app custom_service:binder call; ``` ### 2.8 构建配置 在对应的Android.bp或Makefile中添加构建配置: ```bp // frameworks/base/Android.bp android_library { name: "custom-service", srcs: [ "services/core/java/com/android/server/CustomService.java", "services/core/java/com/android/server/CustomSystemService.java", ], libs: [ "android.app", "android.hardware", ], static_libs: [ "services.core", ], } ``` ## 3. 初始化阶段详解 ### 3.1 阶段1:类加载和实例化 ```java // SystemServiceManager启动服务时发生: CustomSystemService service = new CustomSystemService(context); // -> 创建CustomSystemService实例 // -> 创建CustomService实例 // -> 执行CustomService构造函数中的初始化 ``` ### 3.2 阶段2:服务发布 ```java // onStart()方法被调用时: publishBinderService(Context.CUSTOM_SERVICE, mCustomService); // -> 服务注册到ServiceManager // -> 现在其他进程可以通过ServiceManager.getService("custom_service")获取服务 ``` ### 3.3 阶段3:启动阶段回调 ```java // 系统启动过程中,不同阶段会调用onBootPhase() onBootPhase(PHASE_SYSTEM_SERVICES_READY); // 系统服务就绪 onBootPhase(PHASE_ACTIVITY_MANAGER_READY); // ActivityManager就绪 onBootPhase(PHASE_THIRD_PARTY_APPS_CAN_START); // 第三方应用可启动 onBootPhase(PHASE_BOOT_COMPLETED); // 启动完成 ``` ### 3.4 阶段4:用户相关回调 ```java // 多用户相关回调 onStartUser(int userHandle); // 用户启动 onUnlockUser(int userHandle); // 用户解锁 onStopUser(int userHandle); // 用户停止 ``` ## 4. 客户端访问方式 ### 4.1 系统组件访问方式 ```java // 通过ServiceManager直接访问 ICustomService customService = ICustomService.Stub.asInterface( ServiceManager.getService(Context.CUSTOM_SERVICE)); // 或者通过Context获取 CustomManager customManager = (CustomManager) context.getSystemService( Context.CUSTOM_SERVICE); ``` ### 4.2 创建CustomManager客户端 ```java // frameworks/base/core/java/android/os/CustomManager.java package android.os; import android.content.Context; import android.annotation.SystemService; import android.annotation.RequiresPermission; @SystemService(Context.CUSTOM_SERVICE) public class CustomManager { private final ICustomService mService; public CustomManager(Context context, ICustomService service) { mService = service; } @RequiresPermission(android.Manifest.permission.USE_CUSTOM_SERVICE) public String getConfiguration(String key) { try { return mService.getConfiguration(key); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @RequiresPermission(android.Manifest.permission.MANAGE_CUSTOM_SERVICE) public boolean setConfiguration(String key, String value) { try { return mService.setConfiguration(key, value); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } ``` ## 5. 调试和验证 ### 5.1 服务状态检查 ```bash # 检查服务是否注册 adb shell service list | grep custom # 检查服务运行状态 adb shell dumpsys custom_service # 检查权限设置 adb shell dumpsys package | grep -A5 -B5 custom ``` ### 5.2 日志监控 ```java // 在服务中添加详细的日志记录 Slog.d(TAG, "Service method called with params: " + parameters); Slog.w(TAG, "Unexpected condition: " + condition); Slog.e(TAG, "Error occurred: ", exception); ``` ## 6. 常见问题排查 1. **服务未注册**:检查SystemServer中添加服务的代码是否正确执行 2. **权限拒绝**:检查SELinux策略和权限定义 3. **绑定失败**:检查AIDL接口定义是否一致 4. **启动顺序问题**:确保服务在依赖的服务之后启动
Android SystemServer 中 Service 的创建和启动方式
今天导师给我将讲了一些如何新建一个系统服务,以及如何去初始化。 # Android SystemServer 中 Service 的创建和启动方式 在 Android 系统中,SystemServer 是系统服务的核心进程,负责启动和管理各种系统服务。以下是 SystemServer 中服务创建和启动的详细方式: ## 1. SystemServer 概述 SystemServer 是 Android 系统启动过程中的关键组件,它运行在 `system_server` 进程中,负责启动和管理所有核心系统服务。 ## 2. 服务启动流程 ### 2.1 主要启动阶段 SystemServer 的服务启动分为几个主要阶段: ```java // frameworks/base/services/java/com/android/server/SystemServer.java private void run() { // 1. 启动引导服务 (Bootstrap Services) startBootstrapServices(); // 2. 启动核心服务 (Core Services) startCoreServices(); // 3. 启动其他服务 (Other Services) startOtherServices(); // 4. 系统就绪后的回调 startSystemUi(context); systemReady(); } ``` ### 2.2 引导服务启动 ```java // frameworks/base/services/java/com/android/server/SystemServer.java private void startBootstrapServices() { // 启动 ActivityManagerService mActivityManagerService = ActivityManagerService.Lifecycle.startService( mSystemServiceManager, atm); mActivityManagerService.setSystemProcess(); // 启动 PowerManagerService mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); // 启动 PackageManagerService mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore); // 更多引导服务... } ``` ### 2.3 核心服务启动 ```java private void startCoreServices() { // 启动 BatteryService mSystemServiceManager.startService(BatteryService.class); // 启动 UsageStatsService mSystemServiceManager.startService(UsageStatsService.class); mActivityManagerService.setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class)); // 启动 WebViewUpdateService mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class); // 更多核心服务... } ``` ### 2.4 其他服务启动 ```java private void startOtherServices() { // 启动 WindowManagerService wm = WindowManagerService.main(context, inputManager, !mFirstBoot, mOnlyCore, new PhoneWindowManager(), mActivityManagerService.mActivityTaskManager); ServiceManager.addService(Context.WINDOW_SERVICE, wm, /* allowIsolated= */ false); ServiceManager.addService(Context.INPUT_SERVICE, inputManager); // 启动 NotificationManagerService mSystemServiceManager.startService(NotificationManagerService.class); // 启动自定义服务(如你的 MDM 服务) try { traceBeginAndSlog("StartMdmPolicyManager"); mdmPolicyManager = new MdmPolicyManagerService(context); ServiceManager.addService(Context.MDM_POLICY_SERVICE, mdmPolicyManager); traceEnd(); } catch (Throwable e) { reportWtf("starting Mdm Policy Manager", e); } // 更多其他服务... } ``` ## 3. 服务创建方式 ### 3.1 使用 SystemServiceManager 启动 这是推荐的方式,适用于继承自 `SystemService` 的服务: ```java // 在 SystemServer 中 mSystemServiceManager.startService(YourService.class); // 服务类定义 public class YourService extends SystemService { public YourService(Context context) { super(context); } @Override public void onStart() { // 服务启动逻辑 publishBinderService(Context.YOUR_SERVICE, new YourBinder()); } @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_BOOT_COMPLETED) { // 启动完成后的操作 } } } ``` ### 3.2 直接实例化并注册 对于不继承 `SystemService` 的服务: ```java // 创建服务实例 YourService yourService = new YourService(context); // 添加到 ServiceManager ServiceManager.addService(Context.YOUR_SERVICE, yourService); // 或者使用带权限的添加方式 ServiceManager.addService(Context.YOUR_SERVICE, yourService, false, ServiceManager.DUMP_FLAG_PRIORITY_DEFAULT); ``` ### 3.3 使用静态 main 方法 某些服务有静态的 `main()` 方法: ```java // 服务类中的静态方法 public static YourService main(Context context) { YourService service = new YourService(context); ServiceManager.addService(Context.YOUR_SERVICE, service); return service; } // 在 SystemServer 中调用 YourService.main(mSystemContext); ``` ## 4. 服务生命周期管理 ### 4.1 启动阶段(Boot Phases) 系统服务可以在不同的启动阶段执行初始化: ```java public class YourService extends SystemService { // ... @Override public void onBootPhase(int phase) { if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { // 第三方应用可以启动时的初始化 } else if (phase == PHASE_BOOT_COMPLETED) { // 系统启动完成后的操作 } } } ``` ### 4.2 系统就绪回调 ```java private void systemReady() { // 通知所有服务系统已就绪 mActivityManagerService.systemReady(() -> { // 系统就绪后的操作 }, BOOT_TIMINGS_TRACE_LOG); } ``` ## 5. 自定义服务示例 以下是在 SystemServer 中添加自定义服务的完整示例: ### 5.1 服务接口定义 (AIDL) ```java // frameworks/base/core/java/android/app/IMyCustomService.aidl package android.app; interface IMyCustomService { void doSomething(int param); int getSomething(); } ``` ### 5.2 服务实现 ```java // frameworks/base/services/core/java/com/android/server/MyCustomService.java package com.android.server; import android.app.IMyCustomService; import android.content.Context; import android.os.IBinder; import android.util.Slog; public class MyCustomService extends IMyCustomService.Stub { private static final String TAG = "MyCustomService"; private final Context mContext; public MyCustomService(Context context) { mContext = context; Slog.i(TAG, "MyCustomService created"); } @Override public void doSomething(int param) { Slog.d(TAG, "doSomething called with param: " + param); // 实现具体功能 } @Override public int getSomething() { Slog.d(TAG, "getSomething called"); return 42; // 示例返回值 } } ``` ### 5.3 在 SystemServer 中启动服务 ```java // frameworks/base/services/java/com/android/server/SystemServer.java public final class SystemServer { // ... private void startOtherServices() { // ... // 启动自定义服务 try { traceBeginAndSlog("StartMyCustomService"); MyCustomService myCustomService = new MyCustomService(context); ServiceManager.addService(Context.MY_CUSTOM_SERVICE, myCustomService); traceEnd(); } catch (Throwable e) { reportWtf("starting My Custom Service", e); } // ... } } ``` ### 5.4 在 Context 中定义服务常量 ```java // frameworks/base/core/java/android/content/Context.java public abstract class Context { // ... public static final String MY_CUSTOM_SERVICE = "my_custom_service"; // ... } ``` ## 6. 注意事项 1. **启动顺序**:服务的启动顺序很重要,依赖其他服务的服务应该在依赖服务之后启动 2. **异常处理**:使用 try-catch 块捕获服务启动过程中的异常 3. **性能考虑**:避免在服务启动过程中执行耗时操作 4. **权限控制**:确保服务有适当的权限检查 5. **进程间通信**:如果服务需要跨进程访问,确保正确实现 Binder 接口 ## 7. 调试技巧 1. 使用 `dumpsys` 命令检查服务状态: ```bash adb shell dumpsys my_custom_service ``` 2. 查看服务列表: ```bash adb shell service list ``` 3. 检查系统日志: ```bash adb logcat -s SystemServer ``` 通过以上方式,你可以在 Android SystemServer 中成功创建和启动自定义系统服务。
学习过程中遇到的疑惑问了一下ai,分享出来一起学习一下
在 Android 框架层开发 `DreamInterfaceManager`、`DreamInterfaceService` 和 `DreamInterfaceManager.aidl` 时,它们之间的逻辑关系涉及 **Binder 跨进程通信(IPC)** 和 **服务管理**。这些组件通常用于系统级功能(如设备管理、策略控制等)。 --- ## **1. 组件职责与逻辑关系** | 组件 | 作用 | 关键逻辑 | |------|------|---------| | **`DreamInterfaceManager.aidl`** | **定义 Binder 接口**(客户端 ↔ 服务端通信协议) | 声明远程调用的方法(如 `setWifiPolicy(int)`),供客户端和服务端实现。 | | **`DreamInterfaceService.java`** | **系统服务实现**(运行在 `system_server` 进程) | 继承 `Service` 或 `SystemService`,实现 AIDL 接口的具体逻辑(如调用底层 HAL)。 | | **`DreamInterfaceManager.java`** | **客户端代理**(供 App 或系统模块调用) | 封装 Binder 调用,提供对外的 Java API(内部通过 `IDreamInterface` 调用 `DreamInterfaceService`)。 | --- ## **2. 调用流程(以 `setWifiPolicy(int)` 为例)** ```mermaid sequenceDiagram App/Framework->>DreamInterfaceManager: setWifiPolicy(1) DreamInterfaceManager->>DreamInterfaceService: Binder IPC (transact) DreamInterfaceService->>HAL/Driver: 执行底层操作(如 Wifi 策略设置) HAL/Driver-->>DreamInterfaceService: 返回结果 DreamInterfaceService-->>DreamInterfaceManager: Binder 返回结果 DreamInterfaceManager-->>App/Framework: 返回成功/失败 ``` --- ## **3. 关键实现步骤** ### **(1) 定义 AIDL 接口 (`DreamInterfaceManager.aidl`)** ```java // frameworks/base/core/java/android/server/DreamInterfaceManager.aidl package android.server; interface IDreamInterface { boolean setWifiPolicy(int policy); } ``` - 编译后生成 `IDreamInterface.java`(包含 `Stub` 和 `Proxy` 类)。 --- ### **(2) 实现服务端 (`DreamInterfaceService.java`)** ```java // frameworks/base/services/core/java/com/android/server/DreamInterfaceService.java public class DreamInterfaceService extends IDreamInterface.Stub { @Override public boolean setWifiPolicy(int policy) { // 实际逻辑(如调用 WifiManager) return true; } } ``` - **注册服务**(在 `SystemServer` 中): ```java // frameworks/base/services/java/com/android/server/SystemServer.java public void run() { ... mSystemServiceManager.startService(DreamInterfaceService.class); } ``` --- ### **(3) 实现客户端封装 (`DreamInterfaceManager.java`)** ```java // frameworks/base/core/java/android/server/DreamInterfaceManager.java public class DreamInterfaceManager { private final IDreamInterface mService; public DreamInterfaceManager(Context context) { // 获取 Binder 代理 mService = IDreamInterface.Stub.asInterface( ServiceManager.getService("dream_interface")); } public boolean setWifiPolicy(int policy) { try { return mService.setWifiPolicy(policy); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } ``` --- ## **4. 常见问题与解决** ### **(1) `NullPointerException`(服务未注册)** - **原因**:`DreamInterfaceService` 未在 `SystemServer` 中启动,或客户端未正确获取 Binder 引用。 - **解决**: ```java // 检查服务是否注册 ServiceManager.checkService("dream_interface"); // 或确保 SystemServer 中调用了 startService() ``` ### **(2) `SecurityException`(权限不足)** - **原因**:未在 `AndroidManifest.xml` 或 SELinux 策略中声明权限。 - **解决**: - 在 `DreamInterfaceService` 中添加 `@RequiresPermission` 注解。 - 更新 `sepolicy` 规则(如 `hal_dream_interface_default.te`)。 ### **(3) Binder 调用超时** - **原因**:服务端阻塞(如死锁或耗时操作)。 - **解决**: ```java @Override public boolean setWifiPolicy(int policy) { // 异步执行或优化耗时逻辑 return true; } ``` --- ## **5. 扩展建议** - **使用 `HIDL`/`AIDL` HAL**:如果涉及硬件操作,建议通过 HAL 层实现。 - **添加 SELinux 策略**:确保 `system_server` 和客户端有权限访问服务。 - **日志与调试**:在 `DreamInterfaceService` 中添加 `Slog` 以便追踪问题。 如果需要更具体的实现细节(如 SELinux 规则或 HAL 集成),可以进一步讨论!
APP 上架的临门一脚,差点没迈过去!!
大家好,我是多喝热水。 最近在开发编程导航APP,大家有什么优化点都可以给我提,没有下载体验的可以[下载](https://codefather.cn/post/app)一波! 解答一下大家问的比较多的问题,编程导航 APP 是 Flutter 开发的,大家对开发 APP 感兴趣可以关注一下,后续会持续分享一些 Flutter 专栏内容。 ## 正文 最近 APP 的功能已经做的差不多了,现在正在陆续上架到各大应用商店。当我以为功能开发完了就万事大吉了,其实还有几个大雷等着我踩! <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/f4wfaYRnOHeDyLGS.webp" alt="" width="100%" /> 为什么这么说,因为相关部门对 APP 的隐私问题看的非常重,为了防止一些应用违法过度收集用户信息,在用户未同意 APP 的**隐私政策/用户协议**的情况下不允许收集用户信息。 相信大家在第一次下载 APP 打开的时候,都会需要你授权同意它的隐私政策/用户协议才能让你继续使用。哥们以前还嫌它烦,寻思这玩意有啥用呢,我不同意你就不会获取我的信息了吗?谁信啊,在互联网冲浪谁不是裸奔的。 <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/9zhs7L5ZheBVgxbL.webp" alt="" width="215px" /> 但这事轮到自己头上来才知道,不是别人想加,而是相关部门规定必须加。不过往好处想,也确实能起到一点对用户个人信息保护的作用。但这玩意对开发者来说是真头大。 比如我们在启动应用的时候如果获取了用户设备信息,那不好意思,直接就是:“不通过”。哥们现在看到这三个字都PTSD了。 再者,就是你的代码里没写相关的代码,但是使用的 SDK 获取了。 最难受的来了,我们需要提交的应用市场非常多(每个应用市场需要的材料可能都不一样),第一次提交的时候没意识到隐私合规的重要性,提交的应用市场全部打回,哥们天塌了,又要重新上传。 <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/6J2dKwseonq13C2u.png" alt="" width="225px" /> 后面谨慎一点,先审核一个商店,通过后再处理其他的应用商店,给大家看看我的审核战绩,在经过了 6 次被打回后,终于迎来了曙光: <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/1B6Nd9QnJPoGU4UJ.webp" alt="" width="100%" /> ## 经验 这里分享一些经验(**都很关键**): 1)首先就是需要在隐私政策协议中公示 APP 用到的所有 SDK,描述它们会收集哪些信息,收集这些信息的目的 2)一定要在用户同意隐私政策协议之后才去初始化 SDK 接着我们可以先选一个比较容易审核通过的平台,咱们先上架再说。比较推荐小米,首先是它需要填写的资料不是很多,而且审核效率也很快,客服小姐姐的响应也很及时,审核通过后还能直接同步其他应用商店。 <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/poSrRPNw78fy8BrR.webp" alt="" width="100%" /> 审核不通过的情况我们可以去下载对应的审核日志,如下: <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/QEh37vJFvnFstEYB.webp" alt="" width="100%" /> 在日志里可以看到具体的调用堆栈,根据这些信息可以大致定位到我们的代码,如果是自己代码中的问题,根据调用堆栈日志,大概率可以解决,如下: <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/buynTxrzTmjCJO8G.webp" alt="" width="100%" /> 另外,也可以看到哪些 SDK 在用户没有同意隐私政策之前就触发了收集用户信息的行为,然后去官方文档找找解决方案,没有的话那只能提工单了。 最后,在你改完已知问题之后也可能会出现一些小惊喜(出现一些新的需要整改的点)。 好了,这篇文章就分享到这里,哥们该去看看审核通过没了。 ## 往期文章 [📚 Flutter & H5页面混合开发指北 ](https://www.codefather.cn/post/1864199174536527873) [🤡 因为编辑器没做草稿,老板崩溃了。。。](https://www.codefather.cn/post/1840222330227068929)
Flutter & H5页面混合开发指北
大家好,我是多喝热水。 最近在写 Flutter,简单聊一聊在 Flutter 中如何去集成**H5页面**,读完这篇文章你可以了解以下内容: 1)如何在 Flutter 中加载 H5? 2)Flutter 和 H5 如何进行通信? ## 前言 要在 Flutter 中混入 H5 页面,首先我们需要一个 webview 来加载这个 H5,这里需要用到 [flutter_inappwebview(https://pub.dev/packages/flutter_inappwebview)](https://pub.dev/packages/flutter_inappwebview) 依赖,这个算是 Flutter 中比较优质的三方 webview 库了,功能比较全面: <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/UuImNSw5trrNuPxK.webp" alt="" width="100%" /> ## 使用场景 什么场景下用 webview 性价比最高?说说我的看法: 1)经常会需要变动的页面,比如活动页,H5 有天然的热更新优势 2)不存在大量的逻辑交互,且已经有一套现成的 H5 页面,可以直接套用,避免重复造轮子 ## 实战案例 比如编程导航的[**网页端会员页面**](https://www.codefather.cn/vip)已经适配了移动端,那我们其实没有必要重新写一套,直接拿过来就能用了,只需要解决 Flutter 和 H5 之间的通信问题即可: <img src="https://pic.code-nav.cn/post_picture/1732240055109545986/mVaXXF635EookaGq.webp" alt="undefined" width="312" /> 所以总结一下,我们需要做以下几件事情: 1)安装 flutter_inappwebview 2)加载 webview 3)在 webview 中种上 Cookie(如果有的话) 4)Flutter 与 H5 通信的事件绑定(H5发射事件,flutter监听事件) ### 安装 flutter_inappwebview ```bash flutter pub add flutter_inappwebview ``` ### 加载 webview 这里我们主要关注的点是 `onWebViewCreated` 这个钩子,因为在 webview 创建完成后就可以对事件进行监听(监听来自 H5 发射的事件) ```dart InAppWebView( initialUrlRequest: URLRequest(url: WebUri("https://codefather.cn/vip")), onWebViewCreated: onWebViewCreated, ) ``` ### Cookie 种植 1)我们需要拿到 App 中的 Cookie( token 同理),然后给指定地址种植上,这里我们会用到 `CookieManager` 来种植 Cookie,如下: ```dart // 在 onWebViewCreated 钩子中调用 void onWebViewCreated(InAppWebViewController controller) { setCookies(); } setCookies() { // 1. 实例化 final CookieManager cookieManager = CookieManager.instance(); // 2. 获取 App 中的所有 cookie final cookies = getCookies(); cookies.forEach((key, value) async { await cookieManager.setCookie( url: WebUri("https://codefather.cn/vip"), name: key, value: value, domain: Global.cookieDomain, path: "/api", isSecure: true, maxAge: 3600, ); }) } ``` ### 事件监听(来自H5) 这里我们以开通会员按钮举例,预期是点击开通会员,弹出`"我要开通会员!!!`的提示。 1)Flutter端的监听代码如下 ```dart void onWebViewCreated(InAppWebViewController controller) { // 1. Cookie设置 setCookies(); // 2. 加入会员按钮点击监听 onJoinVip(); } void onJoinVip() { _controller?.addJavaScriptHandler( handlerName: "joinVipHandler", // 监听加入会员事件 callback: (arguments) { showToast("我要开通会员!!!"); }, ); } ``` 2)H5端的代码如下 > 通过 flutter_inappwebview 加载的网页我们可以拿到 flutter_inappwebview 对象,那么我们可以对 window.flutter_inappwebview 做判断,如果它存在我们就认为它是在 flutter 端加载的网页,如果为空,则是走的正常的网页加载,伪代码如下: ```js function h5JoinVip() { if (window.flutter_inappwebview) { // 发射一个加入会员的事件,让flutter去处理这个支付请求 window.flutter_inappwebview.callHandler('joinVipHandler'); } else { H5pay(); // 走h5的支付 } } ``` ## 效果展示 效果已经有了,剩下的就是在 Flutter 中去处理支付流程(但这不是本篇文章的重点): <img src="https://pic.code-nav.cn/migrate_image/ed625eaea89455b0ef180b6aa194b757.gif" alt="效果演示" width="244px" /> 感兴趣的小伙伴可以自己尝试一下,最近会开一个 **Flutter 专栏**,写一些 Flutter 相关的文章,感兴趣的小伙伴可以关注一波,也欢迎关注我的公众号「程序员热水」,我会分享一些前端相关的知识碎片。 --- **往期文章**: - [因为编辑器没做草稿,老板崩溃了。。。](https://www.codefather.cn/post/1840222330227068929) - [这样设计弹框,有更多时间来摸鱼了!](https://www.codefather.cn/post/1818122376005369858) - [👉🏻 更多...](https://www.codefather.cn/user/1732240055109545986/post)
做一个App,可以兼容主流android手机,主流的一些Android 版本呢,需要考虑什么?应该学习什么?
一、问题: 您好,做一个App,可以兼容主流android手机,主流的一些Android 版本呢,需要考虑什么?应该学习什么? 二、背景 我现在开发的App,基本上是定好在一个固定的Android版本、Android机、固定的内存,所以我只需要考虑这一个即可。但如果我面对的不是不同的版本,我应该考虑什么,应该学习什么?想请教一下这个问题。
大三安卓客户端准备找实习求助
### 求职目标 希望成为一名安卓客户端开发人员,想拿到一个中大厂的实习offer ### 个人情况 26毕业河北师范大学本科,想在明年一月份开始投简历面试,有过一年acm经历,算法基础还可以 目前javase没有什么问题,javaee和sping等后端框架学校正在学习中,安卓的技术栈学习了安卓的四大组件,布局的相关内容,常见的一些框架比如okhttp,glide也学完了 数据库相关的mysql和安卓的sqlite学完 暂时还没有做过项目 ### 求职困惑 想问一下,还有什么安卓的技术栈需要补充学习,学完之后有什么项目推荐跟着学习一次的,大概学到什么程度能达成能去实习的这个效果呢 ### 期望帮助 希望得到一些建议 不知道拭心大佬还在不在呀
Termux
地址:https://github.com/termux/termux-app
安卓SDK调试工具
地址:https://developer.android.google.cn/studio/releases/platform-tools?hl=zh-cn
《Android应用开发入门教程》(经典版)
地址:https://pan.baidu.com/s/1vw_JjIzzk0RmeXB1eL0jOQ?pwd=6666
