Cordova插件Android Activity - 访问资源

kel*_*dar 7 android cordova

我正在开发Android的Cordova插件,我很难克服从活动中访问项目资源 - 插件应该是项目独立的,但访问资源(例如R.java)证明是棘手的.

我的插件目前由两个非常简单的类组成:RedLaser.javaRedLaserScanner.java.

RedLaser.java

继承自CordovaPlugin,因此包含该execute方法,看起来类似于以下内容.

public class RedLaser extends CordovaPlugin {
    private static final string SCAN_ACTION = "scan";

    public boolean execute(String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
        if (action.equals(SCAN_ACTION)) {
            this.cordova.getActivity().runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    scan(args, callbackContext);
                }
            });

            return true;
        }

        return false;
    }

    private void scan(JSONArray args, CallbackContext callbackContext) {
        Intent intent = new Intent(this.cordova.getActivity().getApplicationContext(), RedLaserScanner.class);
        this.cordova.startActivityForResult((CordovaPlugin) this, intent, 1);
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        // Do something with the result
    }
}
Run Code Online (Sandbox Code Playgroud)

RedLaserScanner.java

RedLaserScanner包含Android Activity逻辑,并继承自BarcodeScanActivity(这是一个RedLaser SDK类,可能本身继承自Activity);

一个非常简单的结构如下:

public class RedLaserScanner extends BarcodeScanActivity {
    @Override
    public void onCreate(Bundle icicle) {               
        super.onCreate(icicle);

        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                WindowManager.LayoutParams.FLAG_FULLSCREEN);

        setContentView(R.layout.preview_overlay_new_portrait);
    }
}
Run Code Online (Sandbox Code Playgroud)

我遇到了麻烦,因为我需要访问项目的资源来访问R.layout.preview_overlay_new_portrait(它们分散在Eclipse项目中) - 但除非我导入com.myProject.myApp.R,否则我不能这样做- 这使得我的插件依赖于项目本身.

我做了一些调查,发现cordova.getActivity().getResources()它看起来很有用,但是我的RedLaserScanner无法访问它 - 因为它不会从CordovaPlugin继承.

有人可以帮我指点一下吗?

谢谢

Dav*_*lfe 9

我刚遇到同样的问题,结果很容易解决.RedLaserScanner扩展了一个活动,所以你可以像这样调用getResources():

setContentView(getResources("preview_overlay_new_portrait", "layout", getPackageName()));
Run Code Online (Sandbox Code Playgroud)

  • 对于任何对此有疑问的人,请尝试类似`cordova.getActivity()。getResources()。getIdentifier(“ name”,“ layout”,cordova.getActivity()。getPackageName())之类的东西。 (2认同)

Lua*_*uan 5

挂钩可用于替换源文件内容以删除错误的导入和/或添加正确的资源导入。

我创建了一个脚本,无需指定文件即可执行此操作。它尝试查找源文件(带有.java扩展名),删除其中已有的所有资源导入,然后使用 Cordova 应用程序包名称导入正确的资源(如果需要)。

这是脚本:

#!/usr/bin/env node

/*
 * A hook to add resources class (R.java) import to Android classes which uses it.
 */

function getRegexGroupMatches(string, regex, index) {
    index || (index = 1)

    var matches = [];
    var match;
    if (regex.global) {
        while (match = regex.exec(string)) {
            matches.push(match[index]);
            console.log('Match:', match);
        }
    }
    else {
        if (match = regex.exec(string)) {
            matches.push(match[index]);
        }
    }

    return matches;
}

module.exports = function (ctx) {
    // If Android platform is not installed, don't even execute
    if (ctx.opts.cordova.platforms.indexOf('android') < 0)
        return;

    var fs = ctx.requireCordovaModule('fs'),
        path = ctx.requireCordovaModule('path'),
        Q = ctx.requireCordovaModule('q');

    var deferral = Q.defer();

    var platformSourcesRoot = path.join(ctx.opts.projectRoot, 'platforms/android/src');
    var pluginSourcesRoot = path.join(ctx.opts.plugin.dir, 'src/android');

    var androidPluginsData = JSON.parse(fs.readFileSync(path.join(ctx.opts.projectRoot, 'plugins', 'android.json'), 'utf8'));
    var appPackage = androidPluginsData.installed_plugins[ctx.opts.plugin.id]['PACKAGE_NAME'];

    fs.readdir(pluginSourcesRoot, function (err, files) {
        if (err) {
            console.error('Error when reading file:', err)
            deferral.reject();
            return
        }

        var deferrals = [];

        files.filter(function (file) { return path.extname(file) === '.java'; })
            .forEach(function (file) {
                var deferral = Q.defer();

                var filename = path.basename(file);
                var file = path.join(pluginSourcesRoot, filename);
                fs.readFile(file, 'utf-8', function (err, contents) {
                    if (err) {
                        console.error('Error when reading file:', err)
                        deferral.reject();
                        return
                    }

                    if (contents.match(/[^\.\w]R\./)) {
                        console.log('Trying to get packages from file:', filename);
                        var packages = getRegexGroupMatches(contents, /package ([^;]+);/);
                        for (var p = 0; p < packages.length; p++) {
                            try {
                                var package = packages[p];

                                var sourceFile = path.join(platformSourcesRoot, package.replace(/\./g, '/'), filename)
                                if (!fs.existsSync(sourceFile)) 
                                    throw 'Can\'t find file in installed platform directory: "' + sourceFile + '".';

                                var sourceFileContents = fs.readFileSync(sourceFile, 'utf8');
                                if (!sourceFileContents) 
                                    throw 'Can\'t read file contents.';

                                var newContents = sourceFileContents
                                    .replace(/(import ([^;]+).R;)/g, '')
                                    .replace(/(package ([^;]+);)/g, '$1 import ' + appPackage + '.R;');

                                fs.writeFileSync(sourceFile, newContents, 'utf8');
                                break;
                            }
                            catch (ex) {
                                console.log('Could not add import to "' +  filename + '" using package "' + package + '". ' + ex);
                            }
                        }
                    }
                });

                deferrals.push(deferral.promise);
            });

        Q.all(deferrals)
            .then(function() {
                console.log('Done with the hook!');
                deferral.resolve();
            })
    });

    return deferral.promise;
}
Run Code Online (Sandbox Code Playgroud)

只需在您的plugin.xml中添加after_plugin_install挂钩(适用于Android 平台)即可:

<hook type="after_plugin_install" src="scripts/android/addResourcesClassImport.js" />
Run Code Online (Sandbox Code Playgroud)

希望它能帮助别人!