Phonegap 插件活动导入布局
Posted
技术标签:
【中文标题】Phonegap 插件活动导入布局【英文标题】:Phonegap Plugin Activity Import Layout 【发布时间】:2013-11-14 13:25:13 【问题描述】:我正在开发一个有 Activity 的 Cordova 插件,我需要从此 Activity 访问应用程序 R.layout,以便我可以调用 setContentView
。
我目前正在通过创建 import com.example.hello.R
然后在 onCreate method I call
setContentView(R.layout.mysurfaceview)` 上执行此操作:
问题是我的插件只有在应用程序名称为com.example.hello
时才能工作,但我需要在不同的应用程序上安装我的插件,而无需手动进行导入。
有没有办法进行通用导入,例如import <appName>.R
,或任何其他方式来做到这一点?
【问题讨论】:
【参考方案1】:您可以在运行时调用应用程序的资源池,并使用Resources.getIdentifier() 函数按名称引用标识符。此函数需要资源名称、类型和包名称。例如:
String package_name = getApplication().getPackageName();
Resources resources = getApplication().getResources();
setContentView(resources.getIdentifier("my_activity_layout", "layout", package_name));
其中“my_activity_layout”是布局 xml 文件的名称。您还可以以相同的方式引用字符串、可绘制对象和其他资源。一旦你的 Activity 中有这段代码,你就可以在你的 plugin.xml 文件中将你的 Activity 布局文件指定为源文件,并将其设置为复制到 res/layout 文件夹中。
<source-file src="path/to/your/layout/file.xml" target-dir="res/layout"/>
如果您对使用源文件名称有任何其他疑问,请查看Phonegap Plugin Specification。
【讨论】:
我认为挂钩太复杂了,可能不适用于 phonegap 构建。使用 resources.getIdentifier 效果很好。【参考方案2】:我会在构建时使用cordova CLI hook 来修改java import 语句,可能是通过从androidManifest 或config.xml 中解析包的名称。
我不相信有一种方法可以像您询问的那样进行通配符包导入。
【讨论】:
有人找到解决方案了吗?我在这里面临同样的问题! @Sebastian,你试过写一个钩子吗? :不,实际上我以前从未这样做过...你能告诉我从哪里开始吗?谢谢!【参考方案3】:感谢mooreds的回答,
您可以在您的插件中创建一个after_plugin_install
挂钩,如下所示
#!/usr/bin/env node
/*
A hook to add R.java to the draw activiy in Android platform.
*/
var fs = require('fs');
var path = require('path');
var rootdir = process.argv[2];
function replace_string_in_file(filename, to_replace, replace_with)
var data = fs.readFileSync(filename, 'utf8');
var result = data.replace(to_replace, replace_with);
fs.writeFileSync(filename, result, 'utf8');
var target = "stage";
if (process.env.TARGET)
target = process.env.TARGET;
var ourconfigfile = path.join( "plugins", "android.json");
var configobj = JSON.parse(fs.readFileSync(ourconfigfile, 'utf8'));
// Add java files where you want to add R.java imports in the following array
var filestoreplace = [
"platforms/android/src/in/co/geekninja/plugin/SketchActivity.java"
];
filestoreplace.forEach(function(val, index, array)
if (fs.existsSync(val))
console.log("Android platform available !");
//Getting the package name from the android.json file,replace with your plugin's id
var packageName = configobj.installed_plugins["in.co.geekninja.Draw"]["PACKAGE_NAME"];
console.log("With the package name: "+packageName);
console.log("Adding import for R.java");
replace_string_in_file(val,"package in.co.geekninja.plugin;","package in.co.geekninja.plugin;\n\nimport "+packageName+".R;");
else
console.log("No android platform found! :(");
);
并在<platform name="android"> ... </platform>
标签之间添加以下行
<hook type="after_plugin_install" src="hooks/after_plugin_install/hook-add-r-import.js" />
【讨论】:
【参考方案4】:正如@insomniac 所说,钩子可用于替换源文件内容以删除错误的导入和/或添加正确的资源导入。
根据他的回答,我可以创建一个脚本来执行此操作,而无需指定文件。它会尝试查找源文件(扩展名为 .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;
只需在 plugin.xml 中添加一个 after_plugin_install 钩子(适用于 Android 平台):
<hook type="after_plugin_install" src="scripts/android/addResourcesClassImport.js" />
希望它对某人有所帮助!
【讨论】:
以上是关于Phonegap 插件活动导入布局的主要内容,如果未能解决你的问题,请参考以下文章
Google Analytics Phonegap 插件已过时且无法正常工作