【问题标题】:Phonegap Plugin Activity Import LayoutPhonegap 插件活动导入布局
【发布时间】:2013-11-14 13:25:13
【问题描述】:

我正在开发一个有 Activity 的 Cordova 插件,我需要从此 Activity 访问应用程序 R.layout,以便我可以调用 setContentView

我目前正在通过创建 import com.example.hello.R 然后在 onCreate method I callsetContentView(R.layout.mysurfaceview)` 上执行此操作:

问题是我的插件只有在应用程序名称为com.example.hello 时才能工作,但我需要在不同的应用程序上安装我的插件,而无需手动进行导入。

有没有办法进行通用导入,例如import <appName>.R,或任何其他方式来做到这一点?

【问题讨论】:

    标签: android cordova phonegap-plugins


    【解决方案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! :(");
            }
        });
    

    并在&lt;platform name="android"&gt; ... &lt;/platform&gt;标签之间添加以下行

    <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" />
      

      希望它对某人有所帮助!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多