Devlog

Titanium webview and local content

Working with local HTML, Javascript and CSS files in a webview can be very tricky in Titanium Appcelerator for a few reasons:

  • The path to the HTML file is different on iOS and Android.
  • Javascript files are optimized and encrypted during compiling stage. Only Javascript files that are referenced from within HTML files are left untouched. This means that Javascipt files that are loaded dynamically from within Javascript will break.
  • If you include a large Javascript framework in the assets folder, the compiling stage will take very long, because every file will also be handled.

These are the things you can do to make it easier to work with. In the example below I have a “web” directory with the following structure:

web
- index.html
- css
  - style.css
- js
  - app.js

Place your “web” directory into the root of your project. If your Titanium project is located at MyProject, place it in MyProject/web so it is a sibling of the “app” directory with your Alloy views and controllers.

Create a hook that moves this “web” directory to a place your webview can find it after the compilation is finished. This is a very clear and nice solution I saw at JIRA. This has 2 advantages: 1) the compiling takes much shorter to finish because 2) the Javascript files in the “web” directory are left untouched.

To create a new hook:

  • Create a new directory in the plugins directory and name it after the plugin name, for example my.localweb
  • Create an empty my.localweb/plugin.py file – this is to prevent warnings that the plugin cannot be found
  • Create the my.localweb/hooks directory
  • Add this line to the plugins section of the tiap.xml:
    <plugin version="1.0">my.localweb</plugin>
  • Create the file my.localweb/hooks/movelocalweb.js and add the following code:
var path = require("path");
var wrench = require('wrench');

exports.init = function(logger, config, cli, nodeappc) {
 
  if (cli.argv.platform !== 'android') {
 
    logger.log("IOS");
 
    cli.addHook('build.post.compile', function(build, finished) {
 
      logger.log("IOS COPY");
 
      var source = path.join(build.projectDir, "web");
      var destination = path.join(build.xcodeAppDir, "web");
 
      wrench.copyDirSyncRecursive(source, destination, {
        forceDelete: true,
        preserveFiles: false
      });
 
      finished();
 
    });
 
  } else {

    logger.log("ANDROID");
 
    cli.addHook('build.android.writeAndroidManifest',
        function(opts, finished) {
 
      logger.log("ANDROID COPY");
 
      var source = path.join(opts.ctx.projectDir, "web");
      var destination = path.join(opts.ctx.buildDir, "bin",
          "assets", "Resources", "web");

      wrench.copyDirSyncRecursive(source, destination, {
        forceDelete: true,
        preserveFiles: false
      });
 
      finished();
 
    });
  }

};

Now enter the correct path to the index.html file in the webview.

<Alloy>
  <Window>
    <WebView platform="ios" url="/web/index.html" />
    <WebView platform="android" url="../../web/index.html" />
  </Window>
</Alloy>

In the index.html file, you can reference the CSS and Javascript files just as a relative path, for example “css/style.css” or “js/app.js”.