[AIR for Android]彻底解决UC悬浮与AIR项目的兼容性

关于UC的ANE我已经改动很多次了。为了适应Starling的GPU渲染项目(-app.xml中的direct),从登录界面的横竖屏到支付界面的消失 再到悬浮的BUG 一路过来总是那么苛刻。前几天发版本,UC审核人员又把悬浮的问题拿出来说,忍无可忍,没办法只好再次对UC ANE进行修改。这次改动后,悬浮BUG会彻底解决。首先把在接UC SDK过程中遇到的问题先复述一遍:

UC 与AIR项目兼容性BUG

  1. 支付界面竖屏 在横屏的starling项目的时候点击支付会闪退。解决方式是把全部UC界面换成横屏:传送门
  2. 上面这种方式被官方人员彻底否决 于是又有了一种解决方式:传送门
  3. 点击悬浮打开随便一个SDK界面  按下home之后游戏context会丢失,屏幕黑屏(再次按下home再次打开恢复)。解决方式:是 把在flash做悬浮 并固定,把悬浮的回调函数切换到调用个人账户中心 同样需要中转activity;
  4. 阉割版本的flash悬浮图标UC官方无法接受 必须把悬浮恢复原样。这个问题正是本文要讨论的。并解决【3】所描述的BUG;

把悬浮中插入自定义activity的实现

关于UC悬浮与Starling项目的兼容性BUG重现:

限定环境:AIR+Starling+横屏

  • 点击悬浮 随意点进去一个SDK界面 例如 【礼包】;
  • 按下【home】物理键;
  • 再打开AIR应用程序  发现黑屏 游戏界面已消失;
  • 再次按下【home】;
  • 再次打开AIR应用程序 游戏界面恢复;


首先查看UCSDK需要配置的xml参数:

[code lang=”java”]
<!– UC乐视 –>

<activity android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/app_name" android:name="cn.uc.gamesdk.view.SdkWebActivity_s"
android:theme="@android:style/Theme.Translucent"
android:screenOrientation="landscape"
android:windowSoftInputMode="adjustResize" >
<intent-filter >
<action android:name="cn.uc.gamesdk.sdkweb" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
[/code]

显然只有一个activity。也就是说UCSDK所有的界面都是基于这个Activiry;
然后分析 【游戏主activity-悬浮-悬浮打开的界面activity】 之间的关系。结构大概如下图:

按照官方ANE的做法激活悬浮,在代码中活动对象(context.getActiviry())的传输过程如图:

原理是悬浮通过获取游戏主activity的对象去打开上层SDK界面。正是由于传入的是游戏主activity对象给SDK界面 所以在按下home的时候 游戏主activity会在栈堆中被切掉。所以解决这个问题的关键在于在【悬浮-打开SDK界面】的过程中 传入一个新建的activity 而非AIR应用程序主activity。如下图:

这样便可解决开启了direct模式的AIR应用程序 与UC悬浮的兼容性BUG。以下是代码分析

我们知道android java打开activity无非就是startActiviry几个类似的函数。悬浮按钮打开界面也是一样的。

反编译出来UC SDK搜索startActiviry 大概可以定位到这里:
cn.uc.gamesdk.view

[code lang=”java”]
package cn.uc.gamesdk.view;

import android.content.Context;
import android.content.Intent;
import cn.uc.gamesdk.UCUIStyle;
import cn.uc.gamesdk.b.e;
import cn.uc.gamesdk.service.CommonService;
import org.json.JSONException;
import org.json.JSONObject;

public class g
{
private static final String p = "pageTitle";
private static final String q = "pageId";
public static final String a = "uiBusiness";
public static final String b = "login";
public static final String c = "pay";
public static final String d = "userCenter";
public static final String e = "h5EntryKey";
public static final String f = "login";
public static final String g = "pay";
public static final String h = "user_center";
public static final String i = "update_pwd";
public static final String j = "forget_pwd";
public static final String k = "login_game";
public static final String l = "register";
public static final String m = "alpha_code";
public static final String n = "game_not_open";
public static final String o = "nativePageId";

public static void a(String h5EntryKey, String uiBusiness, int pageId, String pageTitle)
{
JSONObject jsonObj = new JSONObject();
try {
jsonObj.put("uiBusiness", uiBusiness);
jsonObj.put("pageId", pageId);
jsonObj.put("pageTitle", pageTitle);
} catch (JSONException e) {
e.printStackTrace();
}
CommonService.currentNativeSourcePageInfo = jsonObj;
a(h5EntryKey, uiBusiness);
}

public static void a(int pageId, String uiBusiness)
{
CommonService.currentNativeSourcePageInfo = null;
b(pageId, uiBusiness);
}

public static boolean a()
{
JSONObject jsonObj = CommonService.currentNativeSourcePageInfo;
if (jsonObj != null) {
int pageId = jsonObj.optInt("pageId");
String uiBusiness = jsonObj.optString("uiBusiness");
a(pageId, uiBusiness);
return true;
}
return false;
}

public static void a(String uiBusiness)
{
if ("login".equals(uiBusiness)) {//SDK登录
if (e.s == UCUIStyle.SIMPLE)
b(1, uiBusiness);
else {
a("login", uiBusiness);
}
return;
}

if ("pay".equals(uiBusiness)) {//SDK支付
a("pay", uiBusiness);
return;
}

if ("userCenter".equals(uiBusiness)) {//SDK个人中心
a("user_center", uiBusiness);
return;
}

a(uiBusiness, uiBusiness);//SDK其他界面 礼包 账户 帮组 攻略等通过悬浮打开的界面
}

private static void a(String h5EntryKey, String uiBusiness)
{
Intent intent = new Intent(e.b, SdkWebActivity.class);
intent.putExtra("h5EntryKey", h5EntryKey);
intent.putExtra("uiBusiness", uiBusiness);
intent.putExtra("activity_work_type", 2);
int flags = 805306368;
intent.setFlags(flags);
e.b.startActivity(intent);
}

private static void b(int nativePageId, String uiBusiness)
{
Intent intent = new Intent(e.b, SdkWebActivity.class);
intent.putExtra("uiBusiness", uiBusiness);
intent.putExtra("nativePageId", nativePageId);
intent.putExtra("activity_work_type", 4);
int flags = 805306368;
intent.setFlags(flags);
e.b.startActivity(intent);
}

public static void b()
{
Intent intent = new Intent(e.b, SdkWebActivity.class);
intent.putExtra("uiBusiness", "pay");
intent.putExtra("activity_work_type", 3);
intent.setFlags(872415232);
e.b.startActivity(intent);
}
}
[/code]

由此可以看出。悬浮打开的界面都通过此函数:

[code lang=”java”]
private static void a(String h5EntryKey, String uiBusiness)
{
Intent intent = new Intent(e.b, SdkWebActivity.class);
intent.putExtra("h5EntryKey", h5EntryKey);
intent.putExtra("uiBusiness", uiBusiness);
intent.putExtra("activity_work_type", 2);
int flags = 805306368;
intent.setFlags(flags);
e.b.startActivity(intent);
}
[/code]

所以只要在此函数中 新建Activiry 然后再传入intent 再启动界面 便可。

然后在UC资源的json中可以发现【账户】【礼包】【攻略】【帮助】等五个界面的key分别为:

账户 user_center
论坛 bbs
礼物 gift
攻略  strategy
帮助 feedback

如此变可把此函数修改为如下:

[code lang=”java”]
private static void a(String h5EntryKey, String uiBusiness)
{
Log.d("h5EntryKey", h5EntryKey);
Log.d("uiBusiness", uiBusiness);

Log.d("Xmsh_isFloat", newAcitvity.isFloat.toString());
//启动新的activity传入Intent newAcitvity 需在-app.xml中定义
//newAcitvity.isFloat 判断当启动的界面是悬浮打开的子界面时再使用 其他一律按照原来的流程
if(newAcitvity.isFloat)
{
Log.d("newAcitvity", "-new—activity—begin–");
newAcitvity.selectKey = 0;
Intent intent = new Intent(newAcitvity.MYACTIVITY_ACTION);
intent.putExtra("selectKey", 0);
intent.putExtra("h5EntryKey", h5EntryKey);
intent.putExtra("uiBusiness", uiBusiness);
if(UCFShowFloatButton_sus.static_context != null)
{
Log.d("newAcitvity", "—static_context–");
UCFShowFloatButton_sus.static_context.getActivity().startActivityForResult(intent, 0);
return;
}

Log.d("newAcitvity", "——static_context is null–");
}

Intent intent_beitai = new Intent(cn.uc.gamesdk.b.e.b, SdkWebActivity_s.class);
intent_beitai.putExtra("h5EntryKey", h5EntryKey);
intent_beitai.putExtra("uiBusiness", uiBusiness);
intent_beitai.putExtra("activity_work_type", 2);
int flags = 805306368;
intent_beitai.setFlags(flags);
cn.uc.gamesdk.b.e.b.startActivity(intent_beitai);
}
[/code]

如此遍解决了这个问题
流程是:
1.复制UC源码库的cn.uc.gamesdk.view.g.java 写入ANE;
2.删除UC 源码库的cn.uc.gamesdk.view.g.java;
3.修改g.java 然后合并jar;

《[AIR for Android]彻底解决UC悬浮与AIR项目的兼容性》有8个想法

  1. 也用了starling?游戏也是横屏?要这两个条件都符合才会引发。ps:这个深恶痛绝的问题昨天终于过了审核。@田小苗

  2. 唉~ 这个wordpress不自动回复邮件的啊?我的游戏有发过你啊,你qq里面搜我的名字。

  3. 你好!这个问题在AIR3.9出来后是不是自动解决了呢?貌似3.9里面有这样一个功能:AIR现在支持了iOS和Android设备在渲染模式设置为”direct”时,在后台执行代码。不知道老兄能不能帮忙测试一下这个问题,这样以后就不用这么这趟解决这些问题了,谢谢!另外,老兄公司的游戏叫什么名字,我想下载下来看一下。我的QQ是414112523,我也是做AIR手游的,希望能和你有进一步的沟通!

  4. 我刚刚看了最新的更新文档。没有说能在direct模式下在后台运行哟。如果要在后台执行代码 其实可以用ane解决。@haicent

  5. Rect你好!很荣幸认识你这样乐于分享的技术大牛,请加一下我的QQ(99755349)。

  6. 补充下,我看的文章大多都是针对android能不能多写一些针对ios的ANE教程呢?我们项目要同时接入这两种,郁闷。。。

  7. 嗯,IOS的ANE比较简单,你去找一本OC基础书,然后结合我博客的几篇仅有的关于IOS ANE的文章 基本上就能解决所有问题了。@Adiers

发表评论

邮箱地址不会被公开。 必填项已用*标注