Email development with React and Webpack

Reading Time: 5 minutes

Email development is often an overlooked practice due to the peculiarities and constraints that most email clients impose.

If you want to deliver a delightful user experience to your product you have to maintain its design consistent across all the media it is consumed from.

An email is one way your product might be consumed from. It is therefore important that you craft your emails sticking to the same design principles you would follow when developing your product in other contexts.

The email world, though, has its own peculiarities, and the constraints the emails have to be built within often lead to design compromises.

My personal experience with email development

A project I was recently involved in had delivered a new look and feel to the product but it required an email to be sent out about it.

We wanted our email to take advantage of the new designs too and, ideally, also of the tools and components we had already built for delivering the new UI.

For this reason, we decided to build an email development pipeline that would help us achieve this goal.

In this blog post I’m going to focus on the use of React and webpack to build HTML templates to be sent as emails.

Even though I mentioned React, the key aspect of this project is really how webpack has been configured to come up with a small email development environment. I’m pretty sure the same configuration can be easily adapted to work with other frameworks.

The constraints

This project had to allow us to re-use React components in our email development. We also wanted to structure it so that it would allow for more than one email template to reuse our existing components library.

Finally, we wanted to be able to produce, as output, a single, standalone HTML file.

Let’s get started

I created and pushed an example project on GitHub. Check it out if you’re impatient 🙂

The project structure

We’re gonna structure the project in a way that allows multiple email templates to be crafted and hosted in the same repository.

.
├── output/
├── package.json
├── README.md
├── src/
│   ├── components/
│   │   └── SectionOutline/
│   │       ├── index.js
│   │       └── index.scss
│   ├── index.js
│   └── templates/
│       └── HelloWorld/
│           ├── index.js
│           ├── index.scss
│           └── index.test.js
├── webpack.config.js
└── yarn.lock
  • The templates folder will contain all the email templates that will be built, pre-rendered and published into the output folder
  • The components folder will contain all the reusable ReactJS components you want to reuse across templates
  • The output folder contains the resulting HTML output of the template you chose to build

webpack.config.js

The webpack configuration file is probably the most important bit in this project. The build configuration will take care of picking the right template to build by injecting all the information it needs and pre-rendering it to HTML.

Let’s start with the header of our webpack.config.js.

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const PrerenderSPAPlugin = require('prerender-spa-plugin');
const HTMLInlineCSSWebpackPlugin = require('html-inline-css-webpack-plugin').default;

As you can see, the configuration is importing a few useful plugins.

In particular, PrerenderSPAPlugin, will take care of pre-rendering the whole template and generate a static HTML out of it. This is achieved using puppeteer behind the scenes.

Another important bit, here, is HTMLInlineCSSWebpackPlugin that will help us convert our css into an internal <style> node within our generated HTML. This is particularly useful for emails.

A dynamic entry

We want to be able to compile a single template out of all the ones available in the templates folder. In order to do this, we will create a function that will return the configuration hash to be exported for the webpack configuration.

const config = (env) => {
  return ({
    mode: 'production',
    entry: {
      // this will be filled in dynamically
    },
    output: {
      filename: '[name].js',
      path: path.join(__dirname, 'output'),
    },
    module: {
      rules: [
        {
          test: /\.(scss|css)$/,
          use: [
            'css-loader',
            'sass-loader',
          ],
        },
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
          },
        },
      ],
    },
    plugins: [
      new PrerenderSPAPlugin({
        staticDir: path.join(__dirname, 'output'),
        indexPath: path.join(__dirname, 'output', `${env.entry}.html`),
        routes: ['/'],
        postProcess: context => Object.assign(context, { outputPath: path.join(__dirname, 'output', `${env.entry}.html`) }),
      }),
      new HtmlWebpackPlugin({
        filename: `${env.entry}.html`,
        chunks: [env.entry],
      }),
      new HTMLInlineCSSWebpackPlugin(),

      // the DefinePlugin helps us defining a const
      // variable that will be 'visible' by the JS code
      // we are rendering at runtime
      new webpack.DefinePlugin({
        "EMAIL_TEMPLATE": JSON.stringify(env.entry),
      }),
    ],
  });
};

As you can see, the mandatory entry field has not been set yet. We will handle it later, and we will require it to be passed in by command line.

The entry will be used to load the right template by passing its value to the PrerenderSPAPlugin. It will also be used to tell HtmlWebpackPlugin how to name the result file.

Finally, we export the configuration the way webpack expects it to be exported:

module.exports = (env) => {
  const entry = {};
  entry[env.entry] = './src/index.js';
  const cfg = config(env);
  cfg.entry = entry;
  return (cfg);
};

Whatever entry we specify, we will always associate it with our entrypoint: index.js.

The index.js file is what is reponsible of loading the template and embedding it into our email layout.

Check out the full webpack.config.js for more information.

A dynamic template

This is the content of the index.js file:

import React, { PureComponent } from 'react';
import ReactDOM from 'react-dom';
import { Box, Item } from 'react-html-email';

/*
 * The EmailContainer will be the body of your Email HTML body.
 * It will receive the right template to load and inject from Webpack
 * and will attempt to load it here and include it in the DOM.
 * 
 * This class expects the EMAIL_TEMPLATE const to be defined.
 */
class EmailContainer extends PureComponent {
  render() {
    // EMAIL_TEMPLATE is defined by the webpack configuration and enables us
    // to include the right template at compile time
    const Template = require(`./templates/${EMAIL_TEMPLATE}`).default;
    return (
      <Box width="600px" height="100%" bgcolor='#f3f3f3' align='center'>
        <Item align='center' valign='top'>
          <Template />
        </Item>
      </Box>
    );
  }
}

ReactDOM.render(<EmailContainer />, document.body);

This is where the magic happens. Every template will be embedded into this code that will produce the final HTML output for the email. As you can see, I am importing a couple of components from the convenient react-html-email project that takes care of providing a few useful components for the email world.

The Template object is dynamically loaded from the EMAIL_TEMPLATE const string that’s expected to be defined when this code is executed. We’re able to do this because we’re using the webpack DefinePlugin:

// the DefinePlugin helps us defining a const
// variable that will be 'visible' by the JS code
// we are rendering at runtime
new webpack.DefinePlugin({
  "EMAIL_TEMPLATE": JSON.stringify(env.entry),
}),

The plugin will take care of setting the const to the full path of the email template I am interested in rendering. In our case the HelloWorld template.

Run it

yarn webpack --env.entry=HelloWorld

The resulting HTML will be stored in the output folder.

browser window html hello world
hello world template rendered result

I know. Not the most beautiful email, but I’ll leave the design to you. 🙂

I hope you enjoyed the post. Let me know if you have any feedback. Don’t forget to check out the full project on GitHub.

Technical debt kills your company

Reading Time: 9 minutes

The early days of a startup are often a chaotic mix of excitement, rush and fear. Software-enabled startups are learning about their product as they iterate with their first customers. This leads to frequent and unplanned changes that will help rapidly evolve their product to fit the market they’re trying to disrupt. Nevertheless, the decisions taken, consciously or unconsciously, on how to evolve their product will inevitably affect their future.

The compromise culture

If you have the chance to live the exciting experience of the early days of a startup as a software engineer, you’ll most likely lead on the technical decisions and will be working hands-on on the code of the product around which the company will be built. And you’ll be the first cause for technical debt.

Technical debt is the compromise you make to get things done faster and grow rapidly. Compromising on quality is justified by the short term goals you want to achieve to establish yourself in the market as soon as possible. You have identified a problem, you’ve found a solution that helps your potential customers do the job and you work hard to sell your solution. But since most startups at such an early stage are just losing money, their focus is mainly around shipping features to sell. This means the tension is all towards rushing to the delivery. Anything stopping you from delivering earlier is an obstacle for the company.

One such obstacle is the “Engineering” bit in Software Engineering.

Engineering is the application of scientific knowledge and mathematical methods to practical purposes of the design, analysis, or operation of structures, machines, or systems. (Wikipedia)

The application of a methodological engineering approach to the crafting of your early stage software product is most likely overkill for any early stage startup because it requires time and thorough thinking. Often, you can’t afford to spend too much time on it because you can’t even be sure what you’re building will be useful to your potential customers.

Conscious vs Unconscious compromise

My code works. I have no idea why.What’s critical in this early stage of the journey is to remain conscious about the compromises you’re going to make to sacrifice quality over speed. Consciousness implies that you’re trying hard to plan to address the technical debt you’re already accumulating. Hoping that the technical debt you’ve accumulated will go away by itself is not a strategy and will end up biting you in the ass as you grow. Worse, not realizing you’re accumulating technical debt will most surely lead to the most painful growth for your engineering organization.

As a good technical leader you should plan for technical debt as if one day your business will be extremely successful.


Planning for technical debt

Not all startups are technological, of course, but if technology is the enabler for your business then you have to make sure technical debt is understood across the company. Understanding the impact technical debt has on your future is hard enough, but it’s especially hard to understand for the less technical people in the company.

As a technical leader, one responsibility you have is ensuring that the state of technical debt is very clear across the board.

If the compromises you’ve made on the quality of the software you’re producing have helped you getting your second client then you’ve only been half-successful as an early-stage startup engineer. The other half of your success resides in making sure the company realizes how much slower you are now on acquiring your third client or on-boarding your next engineer, or fixing that new bug that has just been logged. Every compromise you make has to be clearly understood in order for your future engineering organization to be effective in the next iterations of your product.

Planning for technical debt is definitely not easy and there’s no single success recipe for it. But keeping technical debt in mind should be part of the job of a technical leader. I’ve tried to list a few questions here that it might help to ask yourself from time to time when growing together with the rest of the organization.

  • Are the functionalities of your product documented?
  • Will it work tomorrow when success brings trouble?
  • How much do you know about your software in production?
  • How long will it take for your next hire to get going on the code-base?

Are the functionalities of your product documented?

Goat head issue

Implementing new features and iterating on them happens at a very fast pace in the early stages of a startup. Agreement on what to ship to production often happens verbally between founders and there’s no room for process overhead to formalize those decisions. This means there’s probably no documentation about how your product is behaving for your customers.

Lack of documentation is a form of technical debt. This particular form of technical debt will become hard to address as your company grows and you start hiring more people.

There’s an update your company wants to ship as part of a feature that’s considered very important across the board. This new bit of functionality relies on the existing feature you have implemented in the very early days. You join the conversation and help the new developers understand how the existing functionality behaves. There’s no documentation or automated tests that define how the software in production is behaving so your help is very important at this stage. Your team successfully delivers the change and ships it in production. Everything seems great until one of your customers receives the update and realizes they can’t use the feature they were relying on anymore in the way they intended the feature to be used. Turns out other stakeholders in the company had sold the feature as something else to some of the more recent clients, something not really close to how you expected that feature to be used. Your team now has to rush and “fix” what you have just shipped to restore the old functionality otherwise your most recent client will be very upset.

I’ve seen this happening multiple times. This causes immense frustration across the company and specifically among engineers. It affects the confidence they have in you as a technical lead because you’ve just led them to ship something that has caused more harm than anything. It dramatically impacts the confidence they have in what themselves are shipping to production subsequently. And, undeniably, it affects the perception the other stakeholders in the company have of the engineering organization. Therefore, it is your responsibility to make sure this doesn’t happen.

Documenting is vital for your engineering organization to stay healthy. BDD (Behavior-Driven Development) techniques can really help in this regard as they help you merge the documentation phase with the test phase. This helps you in creating a contract between the functionality and the rest of the organization. It also helps the engineering organization be more confident about changes to the product. Automated tests and documentation help the engineers know what to expect from their changes and it also represents the artifact that defines the product functionality, helping reduce the ambiguity across the company.

Will it work tomorrow when success brings trouble?

Scalability is one of those aspects you might have compromised on in the early days in order to be quicker at delivering. If you’ve done this consciously your company is aware that the current software is not fit for a larger scale yet and will invest resources in scaling it before things go bad. Your role as a technical leader is consult on the planning for resources.

Nowadays this problem seems almost non-existent since the majority of the software runs on managed infrastructures as a service that allow for instant horizontal scaling. And yet, I’ve seen poor technical decisions and insane quantities of technical debt strangling platforms and make them unscalable even if running on cloud platforms.

This can be because of:

  • lack of documentation on specific details to be aware of when scaling
  • insane number of dependencies on third-party providers
  • code base so coupled with the underlying infrastructure that it had hard-coded assumptions on which server it was running on (seriously)
  • asynchronous jobs to be run manually

and so on.

Scalability issues will definitely hit your company if your product is successful. You have to do something to prepare your business to handle the success that it deserves.

Communication is vital for addressing this aspect of the technical debt. Make sure it’s clear across the board every time compromises are being made on the scalability. Be honest to yourself and the rest of the organization about it and act promptly before it’s too late.

How much do you know about your software in production?

Collecting metrics about how your software is doing in production might not seem obvious at the beginning of your startup journey but is vital for your company to be successful. Relying only on your clients to know how it is going is not scalable (see above) and the later you address this the worse it is for your organization.

Measuring is the only way you have to build your organization’s confidence on how the product is being used and how reliable it is in production while at the same time removing any ambiguity around it. Making sure usage patterns and service reliability data points are clearly collected and radiated will help define an unambiguous picture of the software that runs in production, allowing your company to make informed decisions.

Lack of monitoring and instrumentation is not only technical debt: it’s organizational debt. A company that grows without measuring what it does will deliver a product that is the result of the decisions of who shouts the loudest in the organization. And this kind of organizational debt is one of the hardest to address because it shapes the culture of your company.

It’s your responsibility, as a technical leader, to campaign for ensuring that monitoring and instrumentation is adopted as early as possible.

How long will it take for your next hire to get going on the code-base?

As a technical leader you’ll most likely take part in hiring at least the first engineers working on the code that you have crafted for your product to hit the market. You’ll most likely look for someone that fits your company culture and maybe has experience with the technologies your product is currently taking advantage of. But what you should ask yourself, regardless of the type of engineer you’re going to hire, is whether your next hire is going to be able to become autonomous on making changes to the code-base and, ideally, be able to lead future hires as your company grows.

The compromises on the quality, documentation, architecture and sensibility in general of your technological asset will affect the ability of your future hires to impact positively your company. There will be no 10X developer able to overcome insane assumptions on which your software relies on. And this is especially true when your product has been built with technologies that require a high degree of discipline in order to keep everything manageable.

wtfs per minute

Ruby is one of those technologies that I consider requires a high degree of discipline. It gives you the freedom to do pretty much any thing you want. You can easily override any method you like and inject different behavior for already existing functionality pretty much everywhere. From great power comes great responsibility said someone. This is particularly true with this kind of technology.

I’ve seen so many surprising changes to core parts of used libraries that the original intended behavior had completely been altered, leaving newcomers completely knocked out learning how things were behaving completely unpredictably. Someone called this The principle of most surprise and is measurable by the number of WTFs per minute shouted by the developers at work.

This is one of those things I consider to dramatically affect the morale and health of the engineering organization. On top of that, such insensible things are so technical that they are even harder to explain to the rest of the organization when it’s time to address them.

Conclusion

Crafting a product from scratch and building a company around it is not an easy job. The fact that the company turns out to have a market for the product you’ve built is a big success on its own. You should feel proud of it as you’ve been one of the main factors for this success. But different phases in the growth of the company require an adaptive mindset as things evolve. The skillset required to build a company from scratch are different from the ones needed to scale it. And the most important thing is acknowledging this bit.

Technical debt is everywhere and is inevitable. Technical companies will always struggle trying to manage it but the successful ones are the ones that plan for it rather than hoping it goes away by itself.

As you go through the wonderful experience that an early stage startup is, try to think about the questions we’ve just gone through and imagine if things can be done at least slightly better before it’s too late. Try to always question the way you are achieving your results and understand how many shortcuts you’re taking to get there. Pick technologies carefully and be ready to dismiss them as you realize they don’t fit your purpose. Don’t force nasty workarounds to make them work the way they’re not intended to work. Do not blindly fall in love with your code but, rather, be always ready to get rid of it for the better.

Autocomplete engine in Go: let’s build it

Reading Time: 4 minutes

Some time ago I worked on a small autocomplete web service for fun and curiosity. Part of it consists pretty much of what I’m going to talk about in this post.

We’re gonna build a small completion suggester in Go.

A couple of assumptions I’ll have for this experiment are:

  • we don’t care about sub-word matching
  • we want a little typo tolerance
  • we’ll do case-insensitive matching

The prefix-based map

We’re gonna take advantage of PrefixMap, a small map implementation of mine that helps with prefix-based key matching. You may have seen this kind of map called Radix Tree, Trie or Prefix Tree as specified on Wikipedia, but I couldn’t find a naming convention for this kind of tree in the Go land. Maybe you can suggest a better name in the comments.

Anyway, the prefix-based map will be our main data source for suggestions. We’ll use it to store all the suggestions we want to match through our engine.

The Levenshtein distance

We’ll use the Levenshtein distance as a metric to compute how far the typed in string is from the matches that we’ve found. In particular, we’ll define our own similarity metric as:

[code]
levenshtein(match,substr)
1.0 – —————————
max(|match|,|substr|)
[/code]

Where substr is the typed in string and match is the candidate match we have found.

A similarity of 1.0 means that substr and match are equal.

The problem

We have a list of strings that the input will potentially match against. We want to find a few candidate matches that honor a certain similarity threshold we define.

This is a very simplified version of what happens when you start typing text into an auto-completion-enabled input field. Every time you type in, the string you’ve typed in so far gets evaluated against a data source to find the most relevant suggestions for you. And all of this has to happen pretty fast to be effective. You want your auto-completion service to be faster than the user who’s typing so that he can save time and select the suggestion rather than typing it all.

For this particular reason, the implementation of the Prefix Map we’re gonna use will be able to efficiently find all the values for the given prefix. This will save us from having to populate a more traditional map with all possible prefixes for a given key in advance. Instead, thanks to the tree-like structure values will be stored into the map, we’ll be able to just traverse the values in the tree that share a common prefix.

An example solution

For this specific example, our data source is going to be a list of world countries. Our target users will have to select the right country so they will start typing it in and we’ll provide a few suggestions to save them typing.

The autocomplete code

First of all, let’s start from the low-hanging fruits.

We’ve defined our concept of similarity so we’ll start by writing a function for it.

As you can see, the function accepts the ld parameter as one of the inputs. That’s the Levenshtein Distance computed between the words we want to know the similarity of.

Now, let’s populate our PrefixMap with the country list we have. For the purpose of the exercise I’m gonna use the list of country names in English provided by this online service that I’ve turned into a Go slice. You can find a gist for it here.

Now that we have everything we need, let’s work on the main component of our little program: the matching code.

...
        values := datasource.GetByPrefix(strings.ToLower(input))
	results := make([]*Match, 0, len(values))
	for _, v := range values {
		value := v.(string)
		s := similarity(len(value), len(input), LevenshteinDistance(value, input))
		if s >= similarityInput {
			m := &Match{value, s}
			results = append(results, m)
		}
	}

	fmt.Printf("Result for target similarity: %.2f\n", similarityInput)
	PrintMatches(results)
...

We’re taking advantage of the GetByPrefix method from PrefixMap. GetByPrefix will return a flattened collection of all the values in the map that belong to the specified prefix. Pretty handy, isn’t it?

A further filtering I’m applying there, as you can see, is the similarity verification step. I’m going through the list of matches that we have retrieved to filter them according to the similarity input we have received as input in our program.

You can find the full example implementation on GitHub.

The output

This is really it. Here’s a few example invocations of the little code we’ve just written:

$ go run autocompleter.go -similarity 0.3 itlaly

Result for target similarity: 0.30
match: 	Italy	similarity: 0.67
$ go run autocompleter.go -similarity 0.2 united

Result for target similarity: 0.20
match: 	United Arab Emirates	similarity: 0.25	
match: 	United Kingdom	similarity: 0.36	
match: 	United States	similarity: 0.38
$ go run autocompleter.go France

Result for target similarity: 0.30
match: 	France	similarity: 1.00	
match: 	Metropolitan France	similarity: 0.32	

 

Further improvements

As you have seen, our little program allows for little typos in some situations, except when it occurs at the beginning of our input. This is because we’re using a PrefixMap which will not match anything at all if we start with the wrong prefix, of course. An improvement in this sense would probably be to fall back to a full-text search when no matches have been found for the specified similarity in the first pass.

Hopefully this post has been somewhat useful for you, or at least entertaining. Let me know if you need any clarification or if you have to recommend a better approach to achieve this.

Gogoa – Cocoa bindings for Go

Reading Time: 2 minutes

I don’t actually know why but I was wondering how easy it is to integrate Cocoa with Go. Well [SPOILER] looks like it’s super easy!
The first comfortable piece I encountered, actually, was Go 1.3 changelog where it states:

Finally, the go command now supports packages that import Objective-C files (suffixed .m) through cgo.

Since I’m now with Go 1.4.2 I thought: “This should be even easier now!”. Reading through the cgo reference looks like interoperability is getting stronger with Go, despite this comment on SO.

Hahaha… Go’s biggest weakpoint… interoperability. –  Matt JoinerJun 12 ’11 at 13:54

Gimme the code

I know, too much words and no code so far. Turns out that showing a Cocoa window with Go may be as easy as the following:

If you think this is too clean to be true you are kind of right. I actually started this project on GitHub which performs all the ugly bits underneath. I’d really love you to help me get this a little further.

How does it work?

There’s this go tool called cgo which does most of the magic by itself when you build a hybrid project like this. The reference is rather comprehensive but I’d like to highlight a few issues I encountered while wrapping the code up.

1. Keep import “C” after the C statements

Let’s take my application.go as an example:

As you can see import "C" is preceded by three directives as per the cgo standard. Make sure the import "C" directive is right after the actual C directives otherwise your code won’t build. This is because C is a pseudo package generated also using the code you provide through those preceding directives.

2. Always specify the compiler directives

Every file exposing the Objective-C bindings should specify the following flags at least.

// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Cocoa

//#include "g_application.h"

import "C"

Otherwise you would end up in a long long list of compilation errors. At least this is what happened to me.

3. Always void*

If you end up working with pointers to ObjectiveC classes always convert them into void* before returning them back to Go. If you don’t, passing them back to C/ObjectiveC might become painful or you may end up with errors like the following:

struct size calculation error off=8 bytesize=0

At least this is what occurred to me. You may help me see the light with this.

4. Keep the non-Go code in separate files

Although cgo allows for the whole non-Go code to go in the comments, please, don’t do that. You’ll end up in unreadable code. Check out my repository for a possible solution.

Now what?

I don’t know actually. It really took me 1 hour to get this code compiling and running just for the sake of seeing a Cocoa Window. Didn’t expect much more.
Also, I’ve been doing some work with bindings in the past (Qt – Android – JNI, Cocoa – Qt – C++) and it always gets painful when the main framework is not run in the main thread. I don’t know if this will ever the case with Go. I’m not even sure how far this can be pushed especially when it’s about goroutines and defer‘ed stuff. But, despite not so pleasant past experiences I’d like experimenting this with Go and Cocoa as well.

A question for you

How would you write tests for those bindings?

Please, contribute

If you are any interested in this project, please, shout out loud. That would really help me experiment a bit more. Even if you just want to complain about something terribly wrong I did, please, do!

Cheers.

A native iOS app with a Qt third-party library

Reading Time: 4 minutes

I’m wrapping up here pieces of information that I used to setup a working native iOS project taking advantage of a library I wrote mainly using Qt. The library I wrote has nothing to do with GUI, it just helps me dealing with connectivity, REST API interaction, file system access, compression… Also, the library was born for the Desktop but the porting effort to mobile is feasible due to the lack of GUI interaction.
In particular, the following has been tested using Qt 5.3.

Despite the huge integration level now Qt has reached over the year even on the iOS platform, I still prefer having the UI developed using the native SDK. I’m a rather experienced Cocoa developer, not that experienced with Cocoa Touch, but I managed to have everything I needed working. Since the information I found is rather sparse regarding this topic, I thought it could be nice to have everything here in a blog post.

Project info

In the following post I’m assuming you want to link a native iOS Xcode project to a third party library written using C++ and Qt. I’m also assuming you are using statically linked Qt for this project (which is the default for the iOS solution).

So what we have:

  • A native Xcode project for iOS: NativeHelloWorld.xcodeproj
  • A static lib Qt project: FancyStaticLib.pro

What we are going to have

  • NativeHelloWorld.xcodeproj
  • FancyStaticLib.xcodeproj as a subproject to NativeHelloWorld
  • Qt for iOS properly linked to make NativeHelloWorld run and use FancyStaticLib

Let’s get things started

So, first of all let’s instruct Xcode about where to find Qt on our system.
Go to Xcode -> Preferences -> Locations (Tab) -> Source Trees (Sub Tab).
Add the path to your Qt for iOS packages and name it as you wish. I just chose QTLIB_IOS.
Screen Shot 2014-12-18 at 18.25.05

I like setting my paths this way in order to keep my project as “exportable” as possible. This way, other devs can join my project pretty easily.

Now, if you haven’t already, you should create an Xcode project for your static library you want to link into your native iOS project.
In order to do so you have to run something like this:

/path/to/your/Qt/ios/bin/qmake -spec macx-xcode -r /path/to/FancyStaticLib.pro CONFIG+=staticlib CONFIG+=whatever_you_need

This will output FancyStaticLib.xcodeproj file for your static library. You can drag it to your our NativeHelloWorld.xcodeproj inside Xcode and add its product (the static lib) as a link dependency to your project.
NOTE: You will have to re-generate the FancyStaticLib.xcodeproj each time you change your static library .pro file

Link to Qt

Now that we have the project feeling more like a completely native Xcode one we have to set a few things up in order to easily keep developing directly from Xcode through our NativeHelloWorld.xcodeproj

First of all, look for the Headers Search path section in the Build Settings section of your Xcode project:
Screen Shot 2014-12-18 at 18.54.07

We want to make it easy for Xcode to find Qt headers, and also our static lib headers.
Now the variable we previously defined through the Source Trees section in the Xcode preferences comes in handy.
Let’s add the following to the Headers Search Path section:

  • $(QTLIB_IOS)/include
  • /path/to/FancyStaticLib/headers

Now, the actual linker flags.
You will probably need to start your project inside the emulator. When doing so bare in mind that the simulator has a different architecture from your iOS device. Simulator runs an i386 architecture and we want to link our project both to the static Qt lib files compiled for such architecture and for arm. This way we will be able to run our project both in the simulator and on the native device.

Scroll down to the Other Linker Flags section: you should at least have a Debug section. Under Debug, as a child item, you should have Any iOS Simulator SDK. If you don’t, click the little “+” icon on the side of the Debug item and add Any iOS Simulator SDK as child item.Screen Shot 2014-12-18 at 19.06.30

Our project dependencies are satisfied by the following modules:

  • QtCore
  • QtGui
  • QtNetwork
  • QtScript

The Debug section will host the option for running our app on a native device with debug symbols:

-L$(QTLIB_IOS)/lib -lQt5Core_debug -lQt5Gui_debug -lQt5Network_debug -lQt5Script_debug
Also, don’t forget to include proper platform support with:
-lQt5PlatformSupport_debug -L$(QTLIB_IOS)/plugins/ -lqios_debug
You’ll also need -lz -lqtharfbuzzng_debug most probably.
Also, if you are taking advantage of the bearer plugin to handle connectivity, add the following:
-L$(QTLIB_IOS)/plugins/bearer -lqgenericbearer_debug

Now the Any iOS Simulator SDK section:
Simply replace what you typed in the previous section changing “_debug” with “_iphonesimulator_debug” and you are good to go.

The last touch

Your Qt lib will most probably need an instance of QGuiApplication. This usually requires you to replace the default main coming with your project template with a custom one that actually calls QGuiApplication::exec(). Luckily, Qt has made things relatively easy and you won’t need a custom main body. Looks like the Qt guys are cool enough to inject their Qt Event Dispatcher inside the main CocoaTouch run loop making it easy to spawn QTimers and queued methods invocations from Objective-C(++).
Just make sure you initialize a QGuiApplication instance (but you won’t need to call .exec()).

We are going to add the following piece of code inside your application delegate - (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions after having renamed the application delegate file from .m to .mm. Renaming to .mm enables Objective-C++ which helps us mix C++ and Objective-C in the same source.

Conclusions

This is pretty much what is needed to mix a native iOS project with a Qt library. If you encounter linker issues you should be able to easily address them by inspecting the .a symbols you can find inside your $(QTLIB_IOS)/{lib,plugins} directories.
Otherwise please post here your issues so that we can try address them together.

Cheers.

Workaround Windows Tray Area Item Preference

Reading Time: 4 minutes

Introduction

I’m not an experienced Windows developer.
I had to make it clear 🙂

Today I had the chance to implement kind of a nasty hack on Windows.
I had to make my application tray icon always visibile, at least by default. I swear I honor user preference then. I know this is one of those don’tswhen working with Windows API since it is clearly stated in the docs developers have no control over the notification area. But sometimes you feel it deep in your heart that your application user experience would benefit a lot from making your tiny tray icon visible by default. This was my case, and as I can see on the internet, this is the case of a lot of apps out there.

I just wanted to write this down as an excercise to help me get back on sharing what I code (not always feasible, though).

There’s plenty of information out there, it’s just you won’t find a single pice of it and you’ll have to digg a lot before being able to workaround this limitation over the tray area. At least this was my experience as a non-experienced Windows developer.

Now that my reasons have been stated clear we can go ahead and see some code.

Let’s get started

So, there’s this incredible resource by Geoff Chappell which you should check if you want to know more about some undocumented/private APIs on Windows. It looks he has done a huge amount of work around the notification area documenting well enough how to workaround the default limitations exposed by the documented API.

As he states here explorer.exe exposes an ITrayNotify implementation through COM. This interface can be used to know user preferences and status regarding the notification area items. And you of course can also use it to modify such preferences.

So what we are going to do now is requesting the implementation through the canonical CoCreateInstance passing in the required CLSID information. Such information is retrievable from the docs by Geoff. But you can also look for ITrayNotify through regedit.exe in order to find the needed CLSID.

Bringing a few pieces together, here is a quick recap of the declarations you’ll need to make the CoCreateInstance call succeed.

[sourcecode lang=”cpp”]

#ifndef __ITrayNotify_INTERFACE_DEFINED__
#define __ITrayNotify_INTERFACE_DEFINED__

class __declspec(uuid(&quot;FB852B2C-6BAD-4605-9551-F15F87830935&quot;)) ITrayNotify : public IUnknown
{
public:
virtual HRESULT __stdcall
RegisterCallback(INotificationCB* callback) = 0;
virtual HRESULT __stdcall
SetPreference(const NOTIFYITEM* notify_item) = 0;
virtual HRESULT __stdcall EnableAutoTray(BOOL enabled) = 0;
};
#endif // #ifndef __ITrayNotify_INTERFACE_DEFINED__

const CLSID CLSID_TrayNotify = {
0x25DEAD04,
0x1EAC,
0x4911,
{0x9E, 0x3A, 0xAD, 0x0A, 0x4A, 0xB5, 0x60, 0xFD}};

[/sourcecode]

This is enough for requesting the instance through CoCreateInstance. Unfortunately, as I discovered testing my own code, this won’t work on Windows 8 where apparently this private API has changed. You know, this is the drawback of using private APIs :).
Anyway, I spent the day looking for the solution and fortunately I found the appropriate interface also for Windows 8. You can find the same information by running OllyDbg against explorer.exe on Windows 8.

[sourcecode lang=”cpp”]
class __declspec(uuid(&quot;D133CE13-3537-48BA-93A7-AFCD5D2053B4&quot;)) ITrayNotifyWindows8 : public IUnknown
{
public:
virtual HRESULT __stdcall
RegisterCallback(INotificationCB* callback, unsigned long*) = 0;
virtual HRESULT __stdcall UnregisterCallback(unsigned long*) = 0;
virtual HRESULT __stdcall SetPreference(NOTIFYITEM const*) = 0;
virtual HRESULT __stdcall EnableAutoTray(BOOL) = 0;
virtual HRESULT __stdcall DoAction(BOOL) = 0;
};
[/sourcecode]

Getting the instance to the appropriate ITrayNotify interface, though, is not enough. We are going to use another private interface, called INotificationCB, which will help us get the current information regarding our notification item.

So let’s write down our little helper class that will take care of modifying the preferences for our notification item.

[sourcecode lang=”cpp”]
// TinyTrayHelper.h

class TinyTrayHelper : public INotificationCB
{
public:
TinyTrayHelper(NOTIFYICONDATA* nid);
virtual ~TinyTrayHelper();

HRESULT __stdcall Notify(ULONG, NOTIFYITEM *) __override;

bool ensureTrayItemVisible();

ULONG __stdcall AddRef(void) __override;
ULONG __stdcall Release(void) __override;
HRESULT __stdcall QueryInterface(REFIID riid, void **ppvObject) __override;

private:
NOTIFYICONDATA *_nid;
NOTIFYITEM _nit;
wchar_t _exeName[MAX_PATH];
};
[/sourcecode]

Now let’s see the actual implementation for our helper.

[sourcecode lang=”cpp”]
#include &quot;trayhelper.h&quot;

#include &lt;sdkddkver.h&gt;
#include &lt;VersionHelpers.h&gt;

#include &lt;stdio.h&gt;

static void* CreateTrayNotify(bool win8);

TinyTrayHelper::TinyTrayHelper(NOTIFYICONDATA *nid) :
_nid(nid),
_win8(false)
{
CoInitialize(NULL);

::GetModuleFileName(NULL, _exeName, MAX_PATH);

// here we prepare the NOTIFYITEM instance
// that is required to change settings
_nit.exe_name = _exeName;
_nit.guid = _nid-&gt;guidItem;
_nit.hwnd = _nid-&gt;hWnd;
_nit.icon = _nid-&gt;hIcon;
}

TinyTrayHelper::~TinyTrayHelper()
{
}

HRESULT __stdcall TinyTrayHelper::Notify(ULONG, NOTIFYITEM *item)
{
if (item-&gt;hwnd != _nid-&gt;hWnd || item-&gt;guid != _nid-&gt;guidItem) {
// this is a notification about an item that is not ours
// so let’s just ignore it
return S_OK;
}

_nit = NOTIFYITEM(*item);

return S_OK;
}

ULONG __stdcall TinyTrayHelper::AddRef(void)
{
return 1;
}

ULONG __stdcall TinyTrayHelper::Release(void)
{
return 1;
}

HRESULT __stdcall TinyTrayHelper::QueryInterface(REFIID riid, void **ppvObject)
{
if (ppvObject == NULL) return E_POINTER;

if (riid == __uuidof(INotificationCB)) {
*ppvObject = (INotificationCB*)this;
} else if (riid == IID_IUnknown) {
*ppvObject = (IUnknown *) this;
} else {
return E_NOINTERFACE;
}

AddRef();
return S_OK;
}

bool TinyTrayHelper::ensureTrayItemVisible()
{
const bool win8 = IsWindows8OrGreater();
void *trayNotify = CreateTrayNotify();
if (!trayNotify) {
return false;
}

HRESULT hr;
if (win8) {
auto *win8TrayNotify = static_cast&lt;ITrayNotifyWin8*&gt;(trayNotify);
unsigned long callback_id = 0;
// this is synchronous
hr = win8TrayNotify-&gt;RegisterCallback(static_cast&lt;INotificationCB*&gt;(this), &amp;callback_id);
hr = win8TrayNotify-&gt;UnregisterCallback(&amp;callback_id);
} else {
hr = ((ITrayNotify*)trayNotify)-&gt;RegisterCallback(static_cast&lt;INotificationCB*&gt;(this));
hr = ((ITrayNotify*)trayNotify)-&gt;RegisterCallback(NULL);
}

if (FAILED(hr)) {
((IUnknown*)trayNotify)-&gt;Release();
return false;
}

// now we should have an up-to-date information
// about our notification icon item

if (_nit.preference != 0x01) { // this means always hide, so we honor user preference
_nit.preference = 0x02;

if (_win8) {
((ITrayNotifyWin8*)trayNotify)-&gt;SetPreference(&amp;_nit);
} else {
((ITrayNotify*)trayNotify)-&gt;SetPreference(&amp;_nit);
}
}
((IUnknown*)trayNotify)-&gt;Release();
}

static void* CreateTrayNotify(bool win8)
{
CLSID iTrayNotifyCLSID;
if (win8) {
iTrayNotifyCLSID = __uuidof(ITrayNotifyWindows8); // the interface we defined previously
} else {
iTrayNotifyCLSID = __uuidof(ITrayNotify);
}

void *trayNotify;
HRESULT hr = CoCreateInstance (
CLSID_TrayNotify,
NULL,
CLSCTX_LOCAL_SERVER,
iTrayNotifyCLSID,
(PVOID *) &amp;trayNotify);

if (hr == S_OK) {
return trayNotify;
} else {
printf(&quot;Cannot get reference to ITrayNotify instance\n&quot;);
}

return NULL;
}

[/sourcecode]

I see what you did there

So, TinyTrayHelper basically does 4 things here:

  1. Creates a NOTIFYITEM instance based on a NOTIFICATIONDATA instance
  2. Chooses the appropriate ITrayNotify instance based on the current OS
  3. Registers itself as an instace of INotificationCB to receive the relevant information inside the Notify method
  4. Finally calls SetPreference to change the preference regarding the notification area item

What now?

What you need now is just to create an instance of our TinyTrayHelper and pass in your NOTIFICATIONDATA instance reference. Then call ensureTrayIconVisible to change the notification area preference regarding your item.

Please note that I adapted a more complex code to build this example so I didn’t test this code specifically. Use at your own risk.

I hope this will be useful to you. Please, let me know if I made tremendous mistakes here, I’ll try to fix!

Cheers.