为什么在 Cordova InAppBrowser 的 executeScript 回调中无法访问 Angular.js 变量

问题描述:

我正在使用cordova 开发基于angular.js 的混合应用程序.执行以下操作后,我遇到了无法访问角度变量 $(如 $rootScope)的问题.

I am developing hybrid app based on angular.js using cordova. I have faced the problem not accessing to angular variables $ (like $rootScope) after executing the followings.

  1. cordova 和 angular.js 在这个混合应用启动后就完成了初始化.
  2. 当用户点击特定按钮进行社交登录时,将调用以下 loginTwitterAccount $scope 函数.

  1. cordova and angular.js finished to be initialized as soon as this hybrid app is launched.
  2. When user click specific button for social login, the following loginTwitterAccount $scope function is called.

loginTwitterAccount 使用InAppBrowser"cordova 插件打开新窗口以加载外部授权页面,而不是本地.此授权是授权代码"授权类型.因此,如果用户在打开的窗口中授予对我的混合应用程序的访问权限,我的后端服务器会与 twitter 服务器交换访问令牌,然后将访问令牌从 twitter 服务器发送到我的混合应用程序的打开窗口.

loginTwitterAccount opens new window using 'InAppBrowser' cordova plugin to load external authorization page, not local. This authorization is 'Authorization Code' grant type. So if user grants accesses on my hybrid app in opened window, my backend server exchanges access token with twitter server, and then sends access token from twitter server to opened window of my hybrid app.

app.controller('LoginCtrl', function($scope, $rootScope) {
...
  $scope.loginTwitterAccount = function () {
    var ref = $window.open('/auth/login/twitter', '_blank', 'location=yes,toolbar=yes');    
    ref.addEventListener('loadstop', function(event) {
        if (event.url.match('/auth/login/twitter/callback/success')) {
            // content of this url includes access token data explained above.
            // so app can get the data as calling executeScript like the following
            if (event.url.match(successUrl)) {
                ref.executeScript({
                    code: 'getResult();'
                }, function (values) {
                    // I checked values[0].data has correct value that I want.
                    // At the other place, $rootscope.$on for 'social-login' is already registered.
                    $rootscope.$emit('social-login', values[0].data);
                    ref.close();
                });
             }
        }
    });
  };
});

问题是 $rootscope.$emit 不起作用,以及其他带有 $ 的 angular 变量,例如 $scope不行.我不知道为什么在使用cordova和angular.js时会发生这种情况.在这种情况下是否有任何遗漏之处?提前致谢.

The problem is that $rootscope.$emit doesn't work, as well as other angular's variable with $ like $scope doesn't work. I don't know why this happens in the use of cordova and angular.js. Is there any missing points in this case? Thanks in advance.

我发现了上面的问题,因为 $rootScope.$emit 在 angular.js 世界之外被调用.为了解决这个问题,我应该用 $rootScope.$apply 包裹 $rootScope.$emit ,如下所示.

I found the problem above because $rootScope.$emit is called outside angular.js world. To solve the problem, I should wrap $rootScope.$emit with $rootScope.$apply like the following.

        ...
        if (event.url.match(successUrl)) {
            ref.executeScript({
                code: 'getResult();'
            }, function (values) {
                // I checked values[0].data has correct value that I want.
                // At the other place, $rootscope.$on for 'social-login' is already registered.
                $rootScope.$apply(function () {
                    $rootScope.$emit('social-login', values[0].data);
                }
                ref.close();
            });
         }
         ...

您可以在以下链接中找到 $apply 的更多详细信息.

You can find $apply more detail in the following links.

如何在 AngularJS 中使用 $scope.$watch 和 $scope.$apply?

http://jimhoskins.com/2012/12/17/angularjs-and-apply.html