Cordova Android Activity Plugin - Access Resources

I am developing a Cordova plugin for Android, and it is difficult for me to overcome access to project resources due to the action - the plugin must be independent of the project, but access to resources (for example, R.java) is difficult.

My plugin, at the moment, consists of two very simple classes: RedLaser.javaand RedLaserScanner.java.

RedLaser.java

Inherits from CordovaPlugin and therefore contains a method executeand looks something like this:

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
    }
}

RedLaserScanner.java

RedLaserScanner contains the Android activity logic and inherits from BarcodeScanActivity (which is the RedLaser SDK class, presumably itself inherits from Activity);

A very simple structure is as follows:

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);
    }
}

, R.layout.preview_overlay_new_portrait ( Eclipse), , com.myProject.myApp.R, .

cordova.getActivity().getResources(), , RedLaserScanner - CordovaPlugin.

-, , ?

+4
4

, . RedLaserScanner , getResources() :

setContentView(getResources("preview_overlay_new_portrait", "layout", getPackageName()));
+5

, . , config.xml, .

private int getAppResource(String name, String type) {
    return cordova.getActivity().getResources().getIdentifier(name, type, cordova.getActivity().getPackageName());
}

:

getAppResource("app_name", "string");

, , :

this.activity.getString(getAppResource("app_name", "string"))

:

setContentView(getAppResource("preview_overlay_new_portrait", "layout"));

, :

private String getStringResource(String name) {
    return this.activity.getString(
        this.activity.getResources().getIdentifier(
          name, "string", this.activity.getPackageName()));
}

:

this.getStringResource("app_name");

, , , , .

+1

/ .

I created a script that does this without having to specify files. It tries to find the source files (with the .java extension), deletes the resource import that it has already imported, and then inserts the resources they need (if necessary) using the name of the Cordova application package.

This is the script:

#!/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;
}

Just add as hook_upug_install (for the Android platform) to your plugin.xml file:

<hook type="after_plugin_install" src="scripts/android/addResourcesClassImport.js" />

Hope this helps someone!

+1
source

try using android.R.layout.preview_overlay_new_portrait

-1
source

All Articles