常见问题

1、如何解决启动白屏问题?

1.1 应用层集成

首先在style.xml文件中添加以下主题并为启动activity设置该主题

<style name="AppLaunchTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="android:windowFullscreen">true</item>
        <item name="android:windowContentOverlay">@null</item>
        <item name="android:statusBarColor" tools:ignore="NewApi">@android:color/transparent</item>
        <item name="android:windowTranslucentNavigation">true</item>
        <!--splash为drawable目录下的启动图片,必须放置在drawable目录下-->
        <item name="android:background">@drawable/splash</item>
        <!--适配凸凹屏-->
        <item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="o_mr1">shortEdges</item>      
 </style>          
<activity
     android:name="tech.madp.core.DefaultActivity"
     android:theme="@style/AppLaunchTheme"
     tools:replace="android:theme">
     <intent-filter>
       		<action android:name="android.intent.action.MAIN" />

             <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
</activity>

其次在application中定义闪屏回调接口及所需的成员变量

private ViewGroup viewgroup;
// MADP2.0 SDK中内置的自定义闪屏页面(可在应用层自定义以替换SDK中内置的)
private CustomSplashView customSplashView;
// 闪屏图片
private ImageView ivSplash;
// 闪屏页右上角倒计时组件
private CircleProgressbar mCircleProgressbar;

/**
 * MADP2.0 SDK中暴露给应用层的闪屏页接口
 */
private SplashCallBack mSplashCallBack = new SplashCallBack() {
    /**
     * 在weex渲染之前加载
     * @param context 上下文
     * @param seconds 秒数
     * @param imageUrl 后管配置的闪屏图片url
     * @param stageUrl 需要跳转的外部链接url
     */
    @Override
    public void initSplashView(Context context, String seconds, String imageUrl, String stageUrl) {
        viewgroup = ((Activity) context).getWindow().getDecorView().findViewById(android.R.id.content);
        customSplashView = new CustomSplashView(context);
        ivSplash = customSplashView.findViewById(R.id.iv_splash);
        ivSplash.setScaleType(ImageView.ScaleType.FIT_XY);
        mCircleProgressbar = customSplashView.findViewById(R.id.tv_skip);
        if (!TextUtils.isEmpty(seconds)) {
            mCircleProgressbar.setTimeMillis(Long.parseLong(seconds) * 1000);
        }
        FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT);
        Glide.with(context).load(imageUrl).into(ivSplash);
        viewgroup.addView(customSplashView, layoutParams);
    }

    /**
     * 在weex渲染之后加载
     * @param context
     * @param wxsdkInstance
     * @param seconds
     * @param imageUrl
     * @param stageUrl
     */
    @Override
    public void initSplashView(Context context, WXSDKInstance wxsdkInstance, String seconds, String imageUrl, String stageUrl) {

    }

    @Override
    public void onCloseSplash() {
        viewgroup.removeView(customSplashView);
    }

    @Override
    public void renderBegin(WXSDKInstance wxsdkInstance) {

    }
};

最后在application的onCreate方法中注入闪屏回调接口

// 将闪屏回调注入到SDK中以便初始化自定义闪屏页
CustomSplashUtil.getInstance().setSplashCallBack(mSplashCallBack);

1.2 后管配置

启动链设置为导航栏(page_launcher),并在导航栏(page_launcher)场景上设置以下场景参数:

key value desc
x-splash yes 闪屏开关
x-splashSeconds 3 倒计时秒数,例如:3
x-splashImgUrl ../weex/imgs/splash.png 闪屏图片路径,例如:../weex/imgs/splash.png
x-splashStageUrl http://www.baidu.com 闪屏图片点击事件跳转的外链url,例如:http://www.baidu.com
x-placeholderImageResourceName splash 从drawable目录下取的闪屏图片作为placeholderImage使用,只需要配置闪屏图片名即可,不需要.png后缀名 例如:splash
x-fullscreen yes 全屏开关
x-noAnimation yes 关闭转场动画(默认为No)

1、 目前闪屏页只支持weex页面配置,暂不支持web页面;
2、 文档代码为示例代码,应用层可使用原生自定义ui;
3、 需要项目组视情况调整闪屏页逻辑(如:点击广告图跳转场景或外链等)。

2、如何使用Web场景的进度条功能?

在后管中的web场景下配置以下场景参数即可(仅对已配置的web场景生效)

key value desc
x-progressBar yes 进度条开关,yes:显示进度条,no:不显示进度条
x-progressBarHeight 4 进度条高度,默认4像素
x-progressBarBgColor #000000 进度条底色,例如:#000000
x-progressBarPgColor #F3F3F3 进度条已加载部分颜色,例如:#F3F3F3

也可在repo.json中进行以上这些参数的全局配置(对所有web场景均生效)

"defaultprogress_rules" : {
	"x-progressBar" : "yes",
	"x-progressBarHeight" : "4",
	"x-progressBarBgColor" : "#000000",
	"x-progressBarPgColor" : "#F3F3F3",
}

3、如何使用右上角关闭按钮(SDK提供)功能?

在需要配置右上角关闭按钮的场景中配置以下场景参数即可

key value desc
x-rightButton yes 右上角关闭按钮开关,yes:显示按钮,no:不显示按钮
x-closeImageBackgroundResourceName close 右上角关闭按钮图片,支持读取应用层drawable目录下放置的图片资源id名称,不需加图片后缀,例:close;支持将图片放入后管中,例如:./weex/imgs/close.png

可不配置x-closeImageBackgroundResourceName参数,只配置x-rightButton:yes,图片会显示sdk中默认配置的关闭按钮图片。

4、如何应用层自定义右上角关闭按钮?

4.1 应用层集成

在应用层的application的onCreate方法中进行自定义视图的注入,可参考以下代码:

MADPCustomViewManager.getInstance().setCustomViewTemplate(new IMADPCustomViewTemplate() {
            @Override
            public void customCloseContainerChildView(Context context, final ContextPool.MADContext madContext, LinearLayout linearLayout) {
                ImageView imageView = new ImageView(context);
                imageView.setImageResource(R.mipmap.back);
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
                layoutParams.setMargins(50, 55, 0, 0);
                imageView.setLayoutParams(layoutParams);
                imageView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        //关闭场景页面需要调用madContext的finish方法
                        madContext.finish();
                    }
                });
                linearLayout.setOrientation(LinearLayout.VERTICAL);
                linearLayout.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT));
                linearLayout.setGravity(Gravity.LEFT);
                //添加进入容器
                linearLayout.addView(imageView);
            }
        });

4.2 后管配置

在需要配置右上角关闭按钮的场景中配置以下场景参数

key value desc
x-rightButton yes 右上角关闭按钮开关,yes:显示按钮,no:不显示按钮

5、最完整参数列表的初始化方式

	  /**
         * @param app            application对象
         * @param isOpenLog      日志开关 true:开启  false:关闭
         * @param openCockroach  bandage开关(全局异常捕获)
         * @param usePortService 端口开关   true:使用端口进行网络请求   false:使用接口进行网络请求
         * @param launchModel    APP启动时资源的拉取方式是同步还是异步
         * @param httpProxy      代理地址(供抓包时配置)
         * @param grayFlag       传入0表示使用默认的灰度ui(弹框),传入除0之外的其它int类型的值表示自定义灰度ui
         * @param callback       初始化回调
         */
        Engine.initEnvironment(this, true, true, false, MADConfig.LaunchModel.SYNC,
                "", 0, new Engine.InitEnvCallback() {
            @Override
            public void doInitFinish() {

            }
        });

6、如何开启APP启动时的资源同步模式?

首先APP启动时默认开启的是异步模式,如果要强版本一致性,可以开启app启动时的资源同步,这样每次启动app肯定会先同步完资源,再显示页面。略微牺牲启动速度,但更新的资源肯定会生效。

6.1 自定义APP启动时的资源同步loadingUI

如不需要可跳过此步骤,如需要必须在6.2初始化之前进行自定义,在application的onCreate方法中添加以下代码,并按需自定义loadingUI。

不添加以下这段代码,SDK会有一个默认的loadingUI(进度加载框),如果您即不需要自定义loadingUI又不需要默认的loadingUI,那您可以复制以下代码到6.2初始化代码之前,不做具体自定义(空实现)即可。
我们强烈建议您进行自定义APP启动时的资源同步loadingUI,这样可以有效避免在APP资源同步模式下启动时由于拉取资源耗时而导致的白屏现象。

Engine.initResIndexListener(new ResourcIndexingListener() {
            @Override
            public void startIndexing(Activity activity) {
                // 自定义loadingUI

            }

            @Override
            public void indexProgress(Activity activity, int i) {
                // 自定义loadingUI

            }

            @Override
            public void finishIndexing(Activity activity) {
                // 自定义loadingUI
                
            }
        });

6.2 在初始化时传入资源同步更新配置

在application的onCreate方法中进行初始化,并传入资源同步更新配置参数,具体请参考以下代码。

/**
  * @param application
  * @param isOpenLog   日志开关
  * @param OpenCockroach   bandage开关
  * @param LaunchModel   默认异步, MADConfig.LaunchModel.SYNC表示同步
  * @param callback
  */
Engine.initEnvironment(this, true, true, MADConfig.LaunchModel.SYNC, new Engine.InitEnvCallback() {
    @Override
    public void doInitFinish() {

    }
});

7、如何自定义APP同步启动资源更新失败时展示的dialog?

如需自定义此dialog只需在Engine.initEnvironment方法前初始化以下这段代码即可,默认使用SDK自带的弹框。自定义dialog相关代码仅作参考,但“重试”和“退出”两个按钮的点击事件的处理逻辑建议使用示例代码中的。

Engine.initUpdateErrorListener(new UpdateErrorListener() {
    @Override
    public void showCustomDialog(Activity activity, Event event) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.dialog_style);
        builder.setTitle("错误");
        builder.setMessage(event.getName());
        builder.setPositiveButton("重试", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                event.updateChoice(Worker.UpdateRetry);
            }
        });

        builder.setNegativeButton("退出", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                AppManagerDelegate.getInstance().exitApp();
            }
        });
        AlertDialog alertDialog = builder.create();
        alertDialog.setCancelable(false);
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.show();
    }
});

注:dialog的样式请自行实现

8、如何自定义无注册表、SDK未授权、没有配置启动链和sdk输出模式时展示的dialog?

如需自定义此dialog只需在Engine.initEnvironment方法前初始化以下这段代码即可,默认使用SDK自带的弹框。自定义dialog相关代码仅作参考。

Engine.initFatalErrorListener(new FatalErrorListener() {
    @Override
    public void showCustomDialog(Activity activity, Event event) {
        AlertDialog.Builder builder = new AlertDialog.Builder(activity, R.style.dialog_style);
        builder.setTitle("错误");
        builder.setMessage(event.getName());
        builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                // 逻辑实现
            }
        });
        AlertDialog alertDialog = builder.create();
        alertDialog.setCancelable(false);
        alertDialog.setCanceledOnTouchOutside(false);
        alertDialog.show();
    }
});

注:dialog的样式请自行实现

9、网络环境异常时,应用启动优化

弱网或断网状态下资源更新失败重新获取资源或加载本地资源API

调用Engine里的initUpdateErrorListener方法,实现接口。根据应用层弹窗选择条件决定使用哪种API

Engine.initUpdateErrorListener(new UpdateErrorListener() {
            @Override
            public void showCustomDialog(Activity activity, Event event) {
                  //自定义弹窗.....
                //重新加载资源
                event.updateChoice(Worker.UpdateRetry);
                //使用本地资源
                event.updateChoice(Worker.UpdateContinue);
                //退出app
                AppManagerDelegate.getInstance().exitApp();
            }
        });

提示:
    1、预览注册模式不生效,客户端需放置发布注册表。
    2、启动参数应设置为异步模式。
    3、调用时机应放置在启动方法前。

10、web容器白屏检测配置

默认情况下为开启web容器白屏检测,检测到白屏后显示默认错误页API

默认开启白屏检测,检测比例为99.9。如果不想使用此功能,或是想更改检测比例可通过场景参数配置。

在需要配置的web场景中配置以下场景参数(也可全局配置)

支持版本:>=1053

key value desc
x-checkWhitePixel no 白屏检测开关,默认yes:开启功能,no:关闭功能
x-checkWhitePixelScale 99.9 float类型,如99.99999,有效位不能超过7位

自定义白屏后显示的错误页面API

样例:

MADPCustomViewManager.getInstance().setCustomErrorPageTemplate(new CustomErrorPageTemplate() {
            @Override
            public void showWebErrorPage(Context context, ViewGroup viewGroup, WebView webView) {
                View errorPage = LayoutInflater.from(context).inflate(R.layout.customs_web_error, null);
                TextView tvTitle = errorPage.findViewById(R.id.title);
                TextView tvMessage = errorPage.findViewById(R.id.message);
                Button btnNegtive = errorPage.findViewById(R.id.negtive);
                Button btnPositive = errorPage.findViewById(R.id.positive);
                tvTitle.setText("错误提示");
                tvMessage.setText(content);
                btnNegtive.setText("退出");
                btnPositive.setText("重试");
                btnNegtive.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        viewGroup.removeView(errorPage);
                        AppManagerDelegate.getInstance().finishActivity((WebActivity)context);
                    }
                });
                btnPositive.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        viewGroup.removeView(errorPage);
                        webView.reload();
                    }
                });
                RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                        ViewGroup.LayoutParams.MATCH_PARENT);
                viewGroup.addView(errorPage, layoutParams);
            }
        });