tencent cloud

Android 常见问题
最后更新时间:2025-12-19 22:59:37
Android 常见问题
最后更新时间: 2025-12-19 22:59:37

小程序启动失败排查

小程序启动失败,可能有如下几种原因:
原因一:配置文件路径错误,configAssetName 设置的是 assets 目录下文件的完整路径,如果配置文件在子目录下需要追加目录路径,例如:server/tcmpp-android-configurations.json。
原因二:不能修改小程序配置文件内容,否则小程序无法正常运行。
原因三:配置文件中的 packageName 必须与 superapp 的 applicationId 保持一致,否则 superapp 运行失败,因为初始化时会校验配置文件中的 packageName,可以通过如下设置不进行包名校验。
MiniInitConfig config = builder
.verifyPkg(false)//忽略包名校验
.build();


原因四:确定上面初始化注解 @ProxyService 是否生成了如下类 ExtProxyServiceScope:




SDK 如何确保隐私合规?

小程序 SDK 的初始化是在开发者调用 TmfMiniSDK 类的方法时调用的,所以在用户同意隐私合规授权之后,再调用 TmfMiniSDK 类中提供的方法即可。

自定义小程序 API 出现错误,怎么排查?

在编译路径中,检查是否生成 XxxJsPluginScope,如下图:

检查客户端定义的事件与小程序调用方法名是否一致,自定义小程序API的事件名称区分大小写

小程序域名和隐私 API 校验逻辑

小程序使用过程中会校验接口请求域名的合法性,以及如果在管理后台设置了隐私 API 也会进行授权校验,但在如下场景下不进行校验:
运行小程序是非正式版本且小程序开启了 小程序调试

模块化工程支持

当开发者在模块化工程中多个模块同时使用了注解 @JsPlugin 或 @ProxyService 时,Make Project 工程时会出现如下错误:

需要按照如下配置支持多模块化工程:
1. 在每个使用了 @JsPlugin 或 @ProxyService 注解的 module 的 build.gradle 中添加如下代码:
android {
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
//配置模块名:开发者自己定义唯一名称,模块名遵循android类名定义规范
arguments = [tcmppModuleName: "Demo"]
}
}
}
}
2. 初始化代码中注册模块:
@ProxyService(proxy = MiniConfigProxy.class)
public class MiniConfigProxyImpl extends MiniConfigProxy {
@Override
public MiniInitConfig buildConfig() {
MiniInitConfig.Builder builder = new MiniInitConfig.Builder();

//将上面定义的所有module都进行注册,registerModule参数值与上面tcmppModuleName定义的保持一致
return builder


如何查看 SDK 日志输出?

1. 开发者可以在 Android Studio 中,通过关键字 TMF_MINI 过滤得到 SDK 日志。



2. 查看小程序 JS 错误日志。
方式一:开发者可以通过关键字 MINI_JS_LOG 过滤得到 JS 日志。

方式二:Chrome 调试小程序的 JS 是否有错误。


如何打开小程序的调试模式?

为了方便小程序调试查看 log 日志,客户端需要开启小程序调试入口,详情请参见 更多展示列表定义
/**
* 返回胶囊更多面板的按钮,扩展按钮的ID需要设置为[100, 200]这个区间中的值,否则,添加无效
* 注:此方法在小程序进程调用
* @param builder
* @return
*/
public ArrayList<MoreItem> getMoreItems(MoreItemList.Builder builder){
builder.addDebug("调试", icon)//设置控制面板调试按钮
return builder.build();
}
设置后小程序控制面板会出现调试按钮,单击开启调试模式后,重启小程序进入调试模式。


小程序 SDK 会主动清理小程序包缓存吗?

不会,需要开发者自行调用小程序 SDK 提供的小程序删除方法进行清理(删除小程序);如果未主动清理, superapp 的缓存会随着使用小程序数量的增大而增大。

为什么开启R8 full mode 之后无法正常使用小程序?

R8 full mode 混淆由于使用了更为严格的混淆规则,会导致老版本小程序 SDK 部分注解丢失,因而可能无法正常启动小程序。Android Gradle Plugin 自8.0版本起会在编译时强制开启 R8 full mode。请将小程序 SDK mini_core 升级到2.0.5版本以上以兼容 R8 full mode。

web-view 多进程数据目录冲突问题如何解决?

问题说明
web-view 不支持多进程使用相同的数据目录,如果未做特殊处理在多进程中使用 web-view,会有如下报错:

小程序是多进程架构,SDK 内部已经针对该问题做过适配处理了,但由于客户可能会在小程序进程中集成第三方库,部分第三方库没有对 web-view 数据目录做适配工作,所以导致小程序无法正常启动。
处理方法
1. 如果不是必要,建议您不要在小程序进程中集成运行其他三方库,小程序进程判断方法如下:
public class TCMPPDemoApplication extends Application
@Override
public void onCreate() {
super.onCreate();
if (TmfMiniSDK.isMiniProcess(this)) {
// 小程序进程,跳过第三方框架初始化
}
}
}
2. 如果您必须在小程序进程中集成运行其他第三方库,并且第三方库中使用到了 web-view,那么可以通过如下方法修改 web-view 数据目录,修改时机越早越好,避免在 web-view 创建之后再使用该方法。
public class TCMPPDemoApplication extends Application {
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
sApp = this;
// com.tencent.tmfmini.sdk.launcher.DFMWebViewCompat;
DFMWebViewCompat.setDataDirectorySuffix(this);
}
}

部分机型冷启动小程序有短暂黑屏现象

从小程序进程冷启动到进入小程序代理 Activity 生命周期期间,可能因为手机性能或者部分 UI 线程耗时操作,部分手机会展示黑屏,等正常进入 Activity 生命周期后,小程序才正常展示。可以通过为代理 Activity 设置预览背景的方法来避免黑屏,具体做法如下:
1. 通过继承 MiniApp 实现自定义主题,修改默认预览背景,来替换黑屏。
<style name="MyMiniApp" parent="MiniApp">
<!--通过windowDisablePreview设置,打开窗口预览-->
<item name="android:windowDisablePreview">false</item>
<!--通过windowBackground设置您的预览背景-->
<item name="android:windowBackground">#FF0000</item>
</style>
2. 在 AndroidManifest.xml 中修改 MiniActivity 主题为自定义主题。
<activity
tools:replace="android:theme"
android:name="com.tencent.tmfmini.sdk.ui.MiniActivity1"
android:theme="@style/MyMiniApp" />

<activity
tools:replace="android:theme"
android:name="com.tencent.tmfmini.sdk.ui.MiniActivity2"
android:theme="@style/MyMiniApp"/>

<activity
tools:replace="android:theme"
android:name="com.tencent.tmfmini.sdk.ui.MiniActivity3"
android:theme="@style/MyMiniApp" />

<activity
tools:replace="android:theme"
android:name="com.tencent.tmfmini.sdk.ui.MiniActivity4"
android:theme="@style/MyMiniApp"/>

<activity
tools:replace="android:theme"
android:name="com.tencent.tmfmini.sdk.ui.MiniActivity5"
android:theme="@style/MyMiniApp" />
<activity
tools:replace="android:theme"
android:name="com.tencent.tmfmini.sdk.ui.MiniActivity6"
android:theme="@style/MyMiniApp" />

如何设置灰度发布条件?

Superapp 开发者可以通过 SDK 提供的方法设置用户或设备属性,方便在灰度推送等场景下使用。
自定义设备 ID
SDK 初始化时可以通过初始化配置,设置自定义设备 ID,用于在控制台上进行灰度条件的匹配,参考代码如下:
@ProxyService(proxy = MiniConfigProxy.class)
public class MiniConfigProxyImpl extends MiniConfigProxy {
@Override
public MiniInitConfig buildConfig() {
MiniInitConfig.Builder builder = new MiniInitConfig.Builder();
return builder
.configAssetName("tcsas-android-configuration.json")
.deviceUID(ModuleApplet.D_UID)//设置自定义设备 ID
.build();
}
}
设置用户 ID
SDK 提供接口,允许 superapp 设置当前登录的用户账号,用于在控制台上进行灰度条件的匹配,参考代码如下:
/**
* 设置账号信息
*
* @param userId
*/
public static void setUserId(String userId)
TmfMiniSDK.setUserId("xxxxx");

如何以单任务方式启动小程序?

小程序默认使用多任务模式运行,开发者可在启动小程序时通过MiniStartOptions.isSingleTask来指定是否使用单任务模式运行。
public void startMiniApp(String appid) {
//创建小程序启动参数
MiniStartOptions miniStartOptions = new MiniStartOptions();
//将 isSingleTask 变量设置为 true,保证小程序单任务运行
miniStartOptions.isSingleTask = true;
TmfMiniSDK.startMiniApp(activity, appid, MiniScene.LAUNCH_SCENE_SEARCH, MiniApp.TYPE_ONLINE, miniStartOptions);
}
相比多任务模式,单任务有如下限制:
1. 单任务无法在系统任务列表看到单独的小程序,无法在多个小程序和 superapp 之间自由切换。
2. 单任务与 superapp 共用一个任务,无法通过任务管理方式将小程序移动至后台供下次热启动快速返回,关闭小程序会真的销毁小程序运行时,下次重新进入小程序时以冷启动的方式进入。

小程序中调用 superapp 原生页面的几种常见方式

Android 端小程序采用多进程、多任务机制实现,小程序与 superapp 各自运行在独立的进程中,且小程序页面独立于 superapp 处于单独的任务中。基于此背景,小程序中启动原生页面涉及到多种不同的方式,具体方式场景与实现如下示例。
以下示例完整代码实现参看 GitHub demo,可通过 Components 小程序中接口->界面->页面交互查看以下接口效果。
方式1: 小程序同任务启动 Activity 页面
以小程序支付页面举例
注意:
1.在同一任务中启动 Activity 时,需通过 IMiniAppContext.getAttachedActivity() 获取小程序容器 Activity,并以此为上下文启动目标 Activity。
2.启动时切勿使用 FLAG_ACTIVITY_NEW_TASK 标识,该标识会强制创建新任务,违背同任务启动的预期效果。
创建自定义 API mockPayment,小程序端调用后创建模拟支付数据拉起支付页面。
@JsEvent("mockPayment")
public void mockPayment(final RequestEvent req) {
Activity activity = mMiniAppContext.getAttachedActivity();
if (activity.isFinishing()) {
req.fail("app activity already finished");
return;
}
try {
//mock payment default test password 666666
JSONObject mockPayData = mockPayData();
PaymentManager.g().gotoPayPage(activity, mMiniAppContext, mockPayData, (res, data) -> {
QMLog.d("mockPayment", "result: " + data + "; success: " + res);
if (res) {
req.ok(data);
}else {
req.fail("pay failed");
}
});
} catch (JSONException e) {
req.fail("create mock pay data failed");
}
}
PaymentManager 类中依赖当前小程序容器 Activity 将支付页面启动在当前任务中。
public class PaymentManager {
...
//Enter the order payment page
private void gotoPayPage(Activity activity, IMiniAppContext miniAppContext, JSONObject checkRet, AsyncResult result) {
activity.runOnUiThread(() -> {
String fee = checkRet.optString("actualAmount");
double paymentValue = Double.parseDouble(fee) / 10000;
Intent intent = new Intent(activity, PaymentMethodActivity.class);
intent.setAction(Intent.ACTION_VIEW);
intent.putExtra("totalFee", paymentValue);
intent.putExtra("rawData", checkRet.toString());
activity.startActivity(intent);
paymentRequest = new PaymentRequest(miniAppContext, checkRet, result, paymentValue);
Log.e("TAG", "payment request " + this.hashCode());
});
}
}
方式2: 小程序容器 Activity 启动 Dialog 弹窗
以登录授权弹窗举例
注意:
Dialog 组件运行在小程序进程中,若流程中需要与 superapp 进行数据交互或业务协作,需要注意跨进程通信问题。
除了 Android 常用的多进程通信机制,您也可以使用 SDK 内置的 多进程交互 机制进行多进程通信与协作。
创建授权 DialogFragment
public class LoginDialogFragment extends DialogFragment {
private String mMiniAppName;
private AuthListener mAuthListener;

//Used to set login authorization, listen for callbacks
public void setAuthListener(AuthListener authListener) {
mAuthListener = authListener;
}
//...Initialize page and parameters

@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
btnAgree.setOnClickListener(v -> {
// Handle agree button click
// Complete login and authorization operations, and return the username
if (mAuthListener != null) {
mAuthListener.onAuthCallback(true, "Super app user");
}
dismiss();
});
Button btnRefuse = dialog.findViewById(R.id.btn_refuse);
btnRefuse.setOnClickListener(v -> {
// Handle refuse button click
if (mAuthListener != null) {
mAuthListener.onAuthCallback(false, null);
}
dismiss();
});
return dialog;
}


public interface AuthListener {
void onAuthCallback(boolean isAuth, String userName);
}
}
创建自定义 API mockLogin,用于解析登录参数以及 Dialog 展示
1.通过 mMiniAppContext.getAttachedActivity() 获取当前小程序容器 Activity,基于此 Activity 进行 dialog.show()。
2.通过 loginDialogFragment.setAuthListener() 设置授权状态监听,最终结果通过 RequestEvent 对象通知小程序端。

@JsEvent("mockLogin")
public void mockLogin(final RequestEvent req) {
Activity activity = mMiniAppContext.getAttachedActivity();
if (activity.isFinishing()) {
req.fail("app activity already finished");
return;
}
try {
JSONObject jsonObject = new JSONObject(req.jsonParams).optJSONObject("data");
if (jsonObject == null) {
req.fail("ill params");
return;
}
String miniAppName = jsonObject.optString("miniAppName");
LoginDialogFragment loginDialogFragment = LoginDialogFragment.newInstance(miniAppName);
loginDialogFragment.setAuthListener((isAuth, userName) -> {
JSONObject result = new JSONObject();
try {
result.put("isAuth", isAuth);
result.put("userName", userName);
} catch (JSONException e) {
req.fail("auth result illegal params");
}
req.ok(result);
});
loginDialogFragment.show(activity.getFragmentManager(), "login");
} catch (JSONException e) {
req.fail("illegal params");
}
}
方式3: Superapp 任务启动 Activity 页面
部分 Activity 由于属性配置或业务场景特殊,其必须在 superapp 任务启动展示,页面交互完成后需主动调用 backToMiniApp 或 startMiniApp 回到小程序页面,可参考以下示例。
创建 mockRunMainAppPage 自定义接口,用于启动 superapp 同任务 Activity。
@JsEvent("mockRunMainAppPage")
public void mockRunMainAppPage(final RequestEvent req) {
Activity activity = mMiniAppContext.getAttachedActivity();
if (activity.isFinishing()) {
req.fail("app activity already finished");
return;
}
try {
JSONObject params = new JSONObject(req.jsonParams);
String data = params.optString("data");
SameTaskStackActivity.start(activity, data, mMiniAppInfo.appId, mMiniAppInfo.verType);
} catch (JSONException e) {
req.fail("illegal params");
return;
}
req.ok();
}
为 Intent 添加 FLAG_ACTIVITY_NEW_TASK 标识,让其不在小程序任务中启动。
通过监听 Activity Back 事件调用 TmfMiniSDK.backToMiniApp(mMiniAppId, mVerType) 接口回到小程序页面来优化页面切换体验。
public class SameTaskStackActivity extends BaseActivity {
//...other params info
public static void start(Activity activity, String data, String miniAppId, int verType) {
Intent intent = new Intent(activity, SameTaskStackActivity.class);
intent.putExtra(EXTRA_TITLE, data);
intent.putExtra(EXTRA_MINI_APP_ID, miniAppId);
intent.putExtra(EXTRA_VER_TYPE, verType);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.startActivity(intent);
}

@Override
public void onBackPressed() {
super.onBackPressed();
//Monitor the back event and use the backToMiniApp interface to return to the mini program page
//The miniAppId and verType parameters can be obtained through the MiniAppInfo object in BaseJsPlugin
TmfMiniSDK.backToMiniApp(mMiniAppId, mVerType);
}
}


跨进程通信示例

小程序与 superapp 运行在不同的进程中,当小程序需要与 Superapp 页面进行通信时,除了 Android 标准的 IPC 通信机制,还可使用 SDK 内置的 IpcPlugin 机制进行通信,具体使用示例可参看 多进程交互 文档实现跨进程通信。

Android 生物认证如何指定使用面部识别

Android生物认证扩展库基于 Biometric Prompt API 实现,默认指定了BIOMETRIC_STRONG安全级别,发起生物认证时由系统根据该安全级别自动过滤设备支持的认证方式,不支持通过wx.startSoterAuthentication指定具体的认证方式。

本页内容是否解决了您的问题?
您也可以 联系销售 提交工单 以寻求帮助。

文档反馈