One idea, close to the "activation" thing, but easier to deal with IMO, would be to write your own programming software and have EMS use it to program your devices instead of using Microchip tools. It's some work for sure, but definitely doable. There are open source projects for doing just that AFAIK that could serve as basis, and anyway, I think the programming protocols are documented.
Said software could contain the object code for the firmware itself, so you wouldn't need to provide a hex file, and retrieving the code could be made at least significantly harder than just copying a file.
Additionally, this software could add the functionality to generate (and program) a different serial number for each device. Make the software able to only generate unique serial numbers, and only for a predefined range. Once the total number of programmed devices has been reached, the software would not allow programming any further device, so you'd keep control over the number of "manufacturable" products.
In the firmware, you could just add a basic check that the SN has been programmed - probably just a few more bytes of code - (so even if someone manages to somehow extract the code from your programming software, they would still have to understand this additional thing with the SN.) That step would be optional, just a simple additional roadblock. Some PICs can be configured at program time to prevent reading back Flash content as well, so enable this in the config bits.
This way, the object code itself is never provided directly. If you ever need to update the firmware, just send EMS a new version of your programming software; likewise if the predefined number of devices has been reached. It would take a reasonably skilled software guy to do this, but it seems largely doable, and many manufacturing plants will accept using client-provided tools and software (sometimes you don't even have a choice when you use very specific/custom parts.)