Got a similar setup, but using an external 4Mbit SPI Flash, mainly because of speed and size. But should be very similar using I2C.
The basic idea is to have the "Main program" responsible for storing a new firmware into the SPI Flash, in my project the new firmware is sent over-the-air (RF) from a base node. After the new firmware is received and verified a few parameters are stored on a dedicated area of the MCU EEPROM.
Every time the MCU boots the bootloader will read the MCU EEPROM, looking for a new firmware configuration on the same dedicated are, including which address and size the new firmware is stored in the external SPI Flash. If everything is ok the bootloader will run a few CRC checks before and start programming. If no EEPROM info is found, the process logs the error and restart, which will fall-back to the standard Serial Port programming.
The operation result, being an error or success gets logged back into the MCU EEPROM, so the main program will know what happen after the next reset. It happen only once per "new firmware", so the bootloader won't try indefinitely to install the firmware, avoiding to keep writing to EEPROM every boot.
I also included a feature to "factory reset": If the board is powered while holding a button for a few seconds, it check a reserved area of the Flash and, if there's a valid image there, it writes to the board. The "factory firmware" in this case is a "Main program" capable of receiving and storing a new firmware, in other words, you would never need to connect the board to a PC again to program.
All of that is running on top of the OptiBoot and takes around 1.6K and there's probably room for a few optimizations, I just decided to keep the code more readable. The project is based on Atmega328P, so 2K is not that much compared to the functionalities you get. To keep size small, the code doesn't use any Arduino libraries, just a few from the AVR Libc.
Advanced features like, reverting the previous/factory firmware in case the new image is broken, or the new Main Program is unable to contact the base station is also possible.
If you're interested the code for this bootloader and additional documentation, everything will be release very soon, as part of a board launching I'm organizing. You can get more details of those links Bitbucket and Whisper Node - AVR - Wisen