关于UC的ANE我已经改动很多次了。为了适应Starling的GPU渲染项目(-app.xml中的direct),从登录界面的横竖屏到支付界面的消失 再到悬浮的BUG 一路过来总是那么苛刻。前几天发版本,UC审核人员又把悬浮的问题拿出来说,忍无可忍,没办法只好再次对UC ANE进行修改。这次改动后,悬浮BUG会彻底解决。首先把在接UC SDK过程中遇到的问题先复述一遍:
UC 与AIR项目兼容性BUG:
- 支付界面竖屏 在横屏的starling项目的时候点击支付会闪退。解决方式是把全部UC界面换成横屏:传送门,
- 上面这种方式被官方人员彻底否决 于是又有了一种解决方式:传送门
- 点击悬浮打开随便一个SDK界面 按下home之后游戏context会丢失,屏幕黑屏(再次按下home再次打开恢复)。解决方式:是 把在flash做悬浮 并固定,把悬浮的回调函数切换到调用个人账户中心 同样需要中转activity;
- 阉割版本的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分别为:
如此变可把此函数修改为如下:
[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;
我用的他们提供的ane用这好像没你这个问题呢。
也用了starling?游戏也是横屏?要这两个条件都符合才会引发。ps:这个深恶痛绝的问题昨天终于过了审核。@田小苗
唉~ 这个wordpress不自动回复邮件的啊?我的游戏有发过你啊,你qq里面搜我的名字。
你好!这个问题在AIR3.9出来后是不是自动解决了呢?貌似3.9里面有这样一个功能:AIR现在支持了iOS和Android设备在渲染模式设置为”direct”时,在后台执行代码。不知道老兄能不能帮忙测试一下这个问题,这样以后就不用这么这趟解决这些问题了,谢谢!另外,老兄公司的游戏叫什么名字,我想下载下来看一下。我的QQ是414112523,我也是做AIR手游的,希望能和你有进一步的沟通!
我刚刚看了最新的更新文档。没有说能在direct模式下在后台运行哟。如果要在后台执行代码 其实可以用ane解决。@haicent
Rect你好!很荣幸认识你这样乐于分享的技术大牛,请加一下我的QQ(99755349)。
补充下,我看的文章大多都是针对android能不能多写一些针对ios的ANE教程呢?我们项目要同时接入这两种,郁闷。。。
嗯,IOS的ANE比较简单,你去找一本OC基础书,然后结合我博客的几篇仅有的关于IOS ANE的文章 基本上就能解决所有问题了。@Adiers