bang590 / JSPatch

JSPatch bridge Objective-C and Javascript using the Objective-C runtime. You can call any Objective-C class and method in JavaScript by just including a small engine. JSPatch is generally used to hotfix iOS App.
MIT License
11.36k stars 2.24k forks source link

用JSPatch 实现添加JSContext无效! #490

Open Nihility-Ming opened 8 years ago

Nihility-Ming commented 8 years ago

我测试过无数次,用用JSPatch 实现Objective-C原生的JSContext无效!

并且,WebView已经正常初始化了,不存在任何问题。self.context()也能console.log()出内存地址!

我写的代码如下:

defineClass('ActionViewController', {
    webViewDidFinishLoad: function(webView) {

        self.ORIGwebViewDidFinishLoad(webView);

        var weakSelf = __weak(self);

        self.context().setObject_forKeyedSubscript(block(function() {
            dispatch_async_main(function(){
                var vc = SPOfferHomeViewController.viewController();
                weakSelf.navigationController().pushViewController_animated(vc, 1);
            });
        }), "openCustomOffer");

        self.context().setObject_forKeyedSubscript(block(function() {
            dispatch_async_main(function(){
                var vc = SPMarketCenterViewController.viewController();
                weakSelf.navigationController().pushViewController_animated(vc, 1);
            });
        }), "openMarketCenter");

    }
});
bang590 commented 8 years ago

试试用这个 https://github.com/bang590/JSPatch/wiki/performSelectorInOC-%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3

Nihility-Ming commented 8 years ago

听了您的意见,我改成了这样:

defineClass('ActionViewController', {
    webViewDidFinishLoad: function(webView) {

        self.ORIGwebViewDidFinishLoad(webView);

        var weakSelf = __weak(self);

        var b1 = block(function() {
            dispatch_async_main(function(){
                var vc = SPOfferHomeViewController.viewController();
                weakSelf.navigationController().pushViewController_animated(vc, 1);
            });
        });

        return self.context().performSelectorInOC('setObject:forKeyedSubscript:', [b1, "openCustomOffer"], function() {

            var b2 = block(function() {
                dispatch_async_main(function(){
                    var vc = SPMarketCenterViewController.viewController();
                    weakSelf.navigationController().pushViewController_animated(vc, 1);
                });
            });

            return weakSelf.context().performSelectorInOC('setObject:forKeyedSubscript:', [b2, "openMarketCenter"], function() {});

        });
    }
});

但是非常遗憾的是,还是不行?请指教

bang590 commented 8 years ago

试试self.context()也改成用performSelectorInOC,里面那个也是

Nihility-Ming commented 8 years ago
defineClass('ActionViewController', {
    webViewDidFinishLoad: function(webView) {

        self.ORIGwebViewDidFinishLoad(webView);

        var weakSelf = __weak(self);

        return self.performSelectorInOC('context', [], function(con) {
            var b1 = block(function() {
                dispatch_async_main(function(){
                    var vc = SPOfferHomeViewController.viewController();
                    weakSelf.navigationController().pushViewController_animated(vc, 1);
                });
            });

            return con.performSelectorInOC('setObject:forKeyedSubscript:', [b1, "openCustomOffer"], function() {

                var b2 = block(function() {
                    dispatch_async_main(function(){
                        var vc = SPMarketCenterViewController.viewController();
                        weakSelf.navigationController().pushViewController_animated(vc, 1);
                    });
                });

                return con.performSelectorInOC('setObject:forKeyedSubscript:', [b2, "openMarketCenter"], function() {});

            });

        });

    }
});

也是不行噢...😢

bang590 commented 8 years ago

哪一步开始不行呢?调试下

Nihility-Ming commented 8 years ago

用WEB检查器调试过,没有任何语法异常,主要就是不走Block里面的内容,也就是设置JSContext (setObject:forKeyedSubscript:)无效...

bang590 commented 8 years ago

setObject:forKeyedSubscript:传非block有效吗

Nihility-Ming commented 8 years ago

传非Block?总之就是无法响应那个Object了,我试着传递一个字符串对象,还是没有根据Key来响应Object。

以下的代码OC正常,我翻译成JSPatch语法则不行...

    __weak __typeof(self) weakSelf = self;
    [self.context setObject:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            SPOfferHomeViewController *vc = [SPOfferHomeViewController viewController];
            [weakSelf.navigationController pushViewController:vc animated:YES];
        });
    } forKeyedSubscript:@"openCustomOffer"];

    [self.context setObject:^{
        dispatch_async(dispatch_get_main_queue(), ^{
            SPMarketCenterViewController *vc = [SPMarketCenterViewController viewController];
            [weakSelf.navigationController pushViewController:vc animated:YES];
        });
    } forKeyedSubscript:@"openMarketCenter"];
Nihility-Ming commented 8 years ago

大神可以试着写一个简单的Demo噢,可能这个问题还能写入WIKI呢...

action121 commented 8 years ago

@Nihility-Ming @bang590 看了你们的讨论,我试着做了一下,发现这样可以实现。

===oc代码====

import <JSPatch/JPEngine.h>

typedef void(^JSBridgeBlock)(id p0,id p1,id p2,id p3,id p4,id p5,id p6,id p7,id p8,id p9);

@interface MYJSContext :JSContext

@end @implementation MYJSContext

-(void)setObject:(id)object forKeyedSubscript:(NSObject *)key{

JSBridgeBlock evalFunc = object;

JSBridgeBlock callBack = ^(id p0,id p1,id p2,id p3,id p4,id p5,id p6,id p7,id p8,id p9){

    evalFunc(p0,p1,p2,p3,p4,p5,p6,p7,p8,p9);

};
[super setObject:callBack forKeyedSubscript:key];

}

@end

@interface ViewController () @property (strong, nonatomic) UIWebView webview; @property (strong, nonatomic) MYJSContext context; @end

@implementation ViewController

-(void)webViewDidFinishLoad:(UIWebView )webView{ JSValue value = [self.context objectForKeyedSubscript:@"fromjspatch"]; if (value) { [value callWithArguments:@[@[@1,@2,@3],@"3",@"2"]]; } }

@end

====js代码==

defineClass('ViewController', {

        viewDidLoad:function(){

            self.ORIGviewDidLoad();

            var b1 = block("NSArray*,NSString*,NSString*",function(a,b,c) {
                                console.log("from jspatch count:    " + a.count() + "   b: "  + b.toJS() + "    c: " + c.toJS());

                           });

            return self.performSelectorInOC('context', [], function(context) {

                        return context.performSelectorInOC('setObject:forKeyedSubscript:', [b1, "fromjspatch"], function() {});

            });

        }

})

但我不清楚为什么在-(void)setObject:(id)object forKeyedSubscript:(NSObject *)key这个方法里用block重新包一下就正常了,你们如果知道还请解释一下。

billxie1988 commented 8 years ago

我也遇到了类似的问题在JSContext 里面设置的block 没有回调.不过我发现 是这个 [context setObject:@"" forKeyedSubscript:^() {}];没有起到效果

hellovoidworld commented 7 years ago

这个问题解决了吗?我也遇到了这个问题,除了@action121 要增加一个包装类的方法