前言
痛苦的过程,蛋疼的框架,领导安排的任务,只能硬着头皮上。
概述
经过无数次的查找,确定NativeScript默认不支持按键监听。有人说,不支持就不支持呗,我自己写一个呗,好吧,我也是这么想的。
首先需要做的就是如何修改Android工程的源码。
修改原生代码
platform/android
下确实是一个AndroidStudio的工程,但是导入AndroidStudio中却是各种报错,最坑爹的连入口Activity(也就是com.tns.NativeScriptActivity
)都找不到,还有一些gradle的错误。初步估计是NativeScript在编译的过程中会自己先修改Android工程再去编译,所以我们直接导入IDE是不行的,这只是我的猜测。
其实我只要是想在入口Activity中添加onKeyDown即可,没啥其它更多需求,所以,先要找到这个文件。但是,我确定我已经把工程下的每一个文件夹一层层点开去找了,依然没有找到那个com.tns.NativeScriptActivity
,包括各种aar包、jar包我都打开看过,真是奇了怪了。但是生成的apk反编译时是有这个类的。
好吧,既然直接修改你没有办法,那我自己写一个呗,把反编译出来的那个Activity代码全部复制(好在这个反编译出来的代码没有任何语法错误),然后自己写一个同包同名的Activity,运行,结果你应该猜到了,肯定是报dex重复的错误。
再然后,将这个activity改为com.test.WelcomeActivity
,修改app\App_Resources\Android\AndroidManifest.xml
:
<activity
android:name="com.test.WelcomeActivity"
android:label="@string/title_activity_kimera"
android:configChanges="keyboardHidden|orientation|screenSize">
<!--省略其它-->
</activity>
复制运行
然后编译运行,编译是没问题,但是运行报错,可能是js在哪个地方写死了入口Activity导致找不到入口。
再后来在platforms\android\build\nativescript-bindings
下无意中发现了com.tns.NativeScriptActivity.dex
文件,好家伙,总算让我找到了,删掉它,然后自己写一个同名的Activity,并且试着修改了一下里面的代码,好吧,这次终于没问题了,至少有办法修改它的代码了。
2016-11-11更新:貌似这里说错了,上一次不记得怎么就成功了,但是后来试了无数次都不行,因为即使我们把它临时生成的dex文件删除了,重新编译运行时仍然会重新生成,所以依旧会报dex重复错误。
增加按键监听
模仿其它代码,写了个这样的方法:
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)
{
if(event.getAction() != KeyEvent.ACTION_DOWN) return super.onKeyDown(keyCode, event);
Object[] arrayOfObject = { keyCode, event };
Runtime.callJSMethod(this, "onKeydown", Void.TYPE, arrayOfObject);
return super.onKeyDown(keyCode, event);
}
复制
关键就是这个Runtime.callJSMethod
,每个onXXX方法内部都调用了它,比如onStart、onStop、onSaveInstanceState等,表面上看是调用JS方法的意思,但是具体是调用哪里的js、怎么调用的完全不知,跟踪进去看源码也没看懂,折腾了很久最后只能放弃。
在官网API文档找了很久有关事件的东西,依然没有找到什么有价值的信息。
再后来无意中在官网看到一个可以用js重写Activity的方法,然后试了下。在app下面新建一个activity.android.js
,然后像下面这样写:
var frame = require("ui/frame");
var superProto = android.app.Activity.prototype;
var Activity = android.app.Activity.extend("com.test.MainActivity", {
onCreate: function(savedInstanceState) {
if(!this._callbacks) {
frame.setActivityCallbacks(this);
}
// Modules will take care of calling super.onCreate, do not call it here
this._callbacks.onCreate(this, savedInstanceState, superProto.onCreate);
// Add custom initialization logic here
},
onSaveInstanceState: function(outState) {
this._callbacks.onSaveInstanceState(this, outState, superProto.onSaveInstanceState);
},
onStart: function() {
this._callbacks.onStart(this, superProto.onStart);
},
onStop: function() {
this._callbacks.onStop(this, superProto.onStop);
},
onDestroy: function() {
this._callbacks.onDestroy(this, superProto.onDestroy);
},
onBackPressed: function() {
this._callbacks.onBackPressed(this, superProto.onBackPressed);
},
onRequestPermissionsResult: function (requestCode, permissions, grantResults) {
this._callbacks.onRequestPermissionsResult(this, requestCode, permissions, grantResults, undefined);
},
onActivityResult: function (requestCode, resultCode, data) {
this._callbacks.onActivityResult(this, requestCode, resultCode, data, _super.prototype.onActivityResult);
}
});
复制运行
再把AndroidManifest.xml中的Activity的name改成com.test.MainActivity
,运行,嘿嘿,还真可以,到这里才终于恍然大悟:NativeScript的入口Activity是在编译的时候根据JS动态生成的!尼玛!怪不得我找了那么久都找不到。
直接模仿其它方法,写了一个onKeyDown:
onKeyDown: function(keyCode, event)
{
console.log(keyCode);
this._callbacks.onKeyDown(this, keyCode, event, superProto.onKeyDown);
}
复制运行
运行肯定是不行的,报什么错忘了,毕竟肯定没这个简单。
然后全局搜索onRequestPermissionsResult
(因为这个方法和onKeyDown类似有参数),发现只有3个js有相关代码,然后全部模仿着增加了onKeyDown相关方法:
node_modules\tns-core-modules\ui\frame\frame.android.js
:
ActivityCallbacksImplementation.prototype.onSaveInstanceState = function (activity, outState, superFunc) {
superFunc.call(activity, outState);
var view = this._rootView;
if (view instanceof Frame) {
outState.putInt(INTENT_EXTRA, view.android.frameId);
}
};
ActivityCallbacksImplementation.prototype.onKeyDown = function (activity, keyCode, event, superFunc) {
superFunc.call(activity, keyCode, event);
};
复制运行
node_modules\tns-core-modules\ui\frame\frame.d.ts
:
export interface AndroidActivityCallbacks {
onCreate(activity: any, savedInstanceState: any, superFunc: Function): void;
onSaveInstanceState(activity: any, outState: any, superFunc: Function): void;
onStart(activity: any, superFunc: Function): void;
onStop(activity: any, superFunc: Function): void;
onDestroy(activity: any, superFunc: Function): void;
onBackPressed(activity: any, superFunc: Function): void;
onRequestPermissionsResult(activity: any, requestCode: number, permissions: Array<String>, grantResults: Array<number>, superFunc: Function): void;
onActivityResult(activity: any, requestCode: number, resultCode: number, data: any, superFunc: Function);
onKeyDown(activity: any, keyCode: number, event: any, superFunc: Function): void;
}
复制运行
然后再试,还是报错,一个Java的空指针异常:
虽然原生报错了,但是前面我们自己写的那个console.log(keyCode)
却生效了,控制台可以看到输出的键值。
最后还尝试了一些措施,反正都没有成功,尼玛真是彻底崩溃了。我只是想Java调用JS这么一个简单的需求而已,却不知如何做到。
另外发现了默认的Activity生成的jsnode_modules\tns-core-modules\ui\frame\activity.android.js
,默认的入口Activity应该就是根据这个JS生成的。
正在加载评论